SQLite事务与自增深度分析
2017-01-30 10:23
387 查看
SQLite什么都好,就怕“database is locked”这些年来想尽办法去规避它。
测试代码:
View Code
预热环境以后,我们开了两个任务去执行测试函数,间隔1秒。
测试函数负责插入两行数据,间隔3秒。
第一个任务最后会回滚,第二个任务提交。
显然,两个任务会重叠。
比较好奇,任务1申请得到自增1后,任务2申请得到的自增会是多少?
任务1回滚以后,它所申请得到的自增数字如何处理?
结果:
从测试结果来看:
1,任务1申请得到11和12,任务2也是
2,任务1申请得到11后,任务2启动,执行到Insert时阻塞了5.12秒,直到任务1回滚了事务
3,线程15和16是异步写日志,显然它们也被阻塞,线程15阻塞10.519秒,知道任务2提交事务
结论:SQLite执行更新事务操作时使用排它锁,强制自增数字同步分配!
参考: http://sqlite.1065341.n5.nabble.com/Transactions-and-sqlite3-last-insert-rowid-td8905.html
> If I understand it correctly, connection C1 can do an INSERT, get
> ROWID 4, C2 does an INSERT, gets 5, and commits, and then C1 commits,
> with its 4; if C1 rolled back, there's no 4 in the database, just 5
> and whatever else, correct?
>
No, this can't happen. As soon as C1 does its insert, it acquires an
exclusive lock on the database. C2 can't do an insert until C1 either
commits or rolls back and releases the lock. If C1 committed, then C2
will get 5, if C1 rolled back, then C2 will get 4.
测试代码:
static void Test2() { XCode.Setting.Current.TransactionDebug = true; XTrace.WriteLine(Role.Meta.Count + ""); XTrace.WriteLine(Log.Meta.Count + ""); Console.Clear(); Task.Run(() => TestTask(1)); Thread.Sleep(1000); Task.Run(() => TestTask(2)); } static void TestTask(Int32 tid) { try { XTrace.WriteLine("TestTask {0} Start", tid); using (var tran = Role.Meta.CreateTrans()) { var role = new Role(); role.Name = "R" + DateTime.Now.Millisecond; role.Save(); XTrace.WriteLine("role.ID={0}", role.ID); Thread.Sleep(3000); role = new Role(); role.Name = "R" + DateTime.Now.Millisecond; role.Save(); XTrace.WriteLine("role.ID={0}", role.ID); Thread.Sleep(3000); if (tid == 2) tran.Commit(); } } catch (Exception ex) { XTrace.WriteException(ex); } finally { XTrace.WriteLine("TestTask {0} End", tid); } }
View Code
预热环境以后,我们开了两个任务去执行测试函数,间隔1秒。
测试函数负责插入两行数据,间隔3秒。
第一个任务最后会回滚,第二个任务提交。
显然,两个任务会重叠。
比较好奇,任务1申请得到自增1后,任务2申请得到的自增会是多少?
任务1回滚以后,它所申请得到的自增数字如何处理?
结果:
02:45:03.470 6 Y 5 TestTask 1 Start 02:45:03.470 6 Y 5 Transaction.Begin ReadCommitted 02:45:03.486 6 Y 5 Select Count(*) From Role Where Name='R470' 02:45:03.501 6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R470', 0, '');Select last_insert_rowid() newid 02:45:03.517 6 Y 5 开始初始化实体类UserX 02:45:03.517 6 Y 5 完成初始化实体类UserX 02:45:03.533 6 Y 5 role.ID=11 02:45:04.486 14 Y 6 TestTask 2 Start 02:45:04.486 14 Y 6 Transaction.Begin ReadCommitted 02:45:04.486 14 Y 6 Select Count(*) From Role Where Name='R486' 02:45:04.486 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid 02:45:05.251 15 Y 7 Transaction.Begin ReadCommitted 02:45:05.251 15 Y 7 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid 02:45:06.548 6 Y 5 Select Count(*) From Role Where Name='R548' 02:45:06.548 6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R548', 0, '');Select last_insert_rowid() newid 02:45:06.548 6 Y 5 role.ID=12 02:45:09.555 6 Y 5 Transaction.Rollback ReadCommitted 02:45:09.555 6 Y 5 TestTask 1 End 02:45:09.618 14 Y 6 SQL耗时较长,建议优化 5,120毫秒 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid 02:45:09.618 14 Y 6 role.ID=11 02:45:12.633 14 Y 6 Select Count(*) From Role Where Name='R633' 02:45:12.633 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R633', 0, '');Select last_insert_rowid() newid 02:45:12.633 14 Y 6 role.ID=12 02:45:15.649 14 Y 6 Transaction.Commit ReadCommitted 02:45:15.649 14 Y 6 TestTask 2 End 02:45:15.774 15 Y 7 SQL耗时较长,建议优化 10,519毫秒 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid 02:45:15.774 15 Y 7 Transaction.Commit ReadCommitted 02:45:16.622 16 Y 9 Transaction.Begin ReadCommitted 02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:06', 'ID=12,Name=R548');Select last_insert_rowid() newid 02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:09', 'ID=11,Name=R486');Select last_insert_rowid() newid 02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:12', 'ID=12,Name=R633');Select last_insert_rowid() newid 02:45:16.637 16 Y 9 Transaction.Commit ReadCommitted
从测试结果来看:
1,任务1申请得到11和12,任务2也是
2,任务1申请得到11后,任务2启动,执行到Insert时阻塞了5.12秒,直到任务1回滚了事务
3,线程15和16是异步写日志,显然它们也被阻塞,线程15阻塞10.519秒,知道任务2提交事务
结论:SQLite执行更新事务操作时使用排它锁,强制自增数字同步分配!
参考: http://sqlite.1065341.n5.nabble.com/Transactions-and-sqlite3-last-insert-rowid-td8905.html
> If I understand it correctly, connection C1 can do an INSERT, get
> ROWID 4, C2 does an INSERT, gets 5, and commits, and then C1 commits,
> with its 4; if C1 rolled back, there's no 4 in the database, just 5
> and whatever else, correct?
>
No, this can't happen. As soon as C1 does its insert, it acquires an
exclusive lock on the database. C2 can't do an insert until C1 either
commits or rolls back and releases the lock. If C1 committed, then C2
will get 5, if C1 rolled back, then C2 will get 4.
相关文章推荐
- SQL Server事务、隔离级别详解(二十九)
- SpringBoot缓存注解学习笔记之Redis
- Salesforce使用truncate清空数据库
- mysql 协议的processInfo命令包及解析
- 编译安装mysql5.6并初始化数据库和创建系统服务
- nodejsmysqlconnectiontutorial
- SQL 共享之 ROLL_INVALID_MISMATCH 含义
- Oracle Index Merge 与 and_equal 的变迁
- centos6.5 安装redis3.0.7
- nginx+Redis+tomcat实现session共享的过程
- SpringBoot缓存注解学习笔记之Redis
- ehcache memcache redis 三大缓存对比
- 谈一谈redis集群(二)
- mysql更改数据存储地址
- 习课的redis配置记录
- 后台(03)——MySQL(3)
- sqlmap --tamper 绕过WAF脚本分类整理
- mysql-ERROR 2002 (HY000)
- MySQL学习笔记-用户管理例子
- MySQL2