专栏首页智能大石头SQLite事务与自增深度分析

SQLite事务与自增深度分析

SQLite什么都好,就怕“database is locked”这些年来想尽办法去规避它。 测试代码:

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);
    }
}

预热环境以后,我们开了两个任务去执行测试函数,间隔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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [NewLife.XCode]增删改查入门

    NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。

    大石头
  • MF前传——探索者二号简介

        因为探索者一号供不应求,远超预期,并且我们自己设计制造的成本太高,所以没有再次生产。而是选择较高性价比的第三方STM32开发板作为MF学习板,是为探索者...

    大石头
  • XCode新增数据转换功能(导数据)

    用法: DAL.AddConnStr("xxgk", "Data Source=192.168.1.21;Initial Catalog=信息公开;user i...

    大石头
  • 它会不会成为OCR领域霸主?经过一个月的分析,我得出了这些结论

    赛题链接:http://www.cnsoftbei.com/plus/view.php?aid=516

    TrueDei
  • Linux连接投影仪(ubuntu)失败或显示不正常--未测试

    Linux连接投影仪,网上这方便的资料比较少,尤其是图文资料。最近有这方面的需求,查了很多的资料,最终实现的投影。直接插上VGA后,发现屏幕显示的不正确,或不显...

    双面人
  • Quick-Task 动态脚本支持框架之任务动态加载

    前面几篇博文分别介绍了整个项目的基本架构,使用说明,以及整体框架的设计与实现初稿,接下来则进入更细节的实现篇,将整个工程中核心实现捞出来,从为什么这么设计到最终...

    一灰灰blog
  • 我用Python算出了同事的身份证号码 | 原力计划

    可以用来验证身份证号合法性、获取身份证号信息、生成可通过校验的假数据、身份证升级。

    AI科技大本营
  • 我用python算出了同事的身份证号码!

    可以用来验证身份证号合法性、获取身份证号信息、生成可通过校验的假数据、身份证升级。

    龙哥
  • 我用python算出了同事的身份证号码!

    可以用来验证身份证号合法性、获取身份证号信息、生成可通过校验的假数据、身份证升级。

    朱小五
  • 我用python算出了同事的身份证号码!

    可以用来验证身份证号合法性、获取身份证号信息、生成可通过校验的假数据、身份证升级。

    jeanron100

扫码关注云+社区

领取腾讯云代金券