【问题标题】:sqlite only supports 1 transaction?sqlite 只支持 1 笔交易?
【发布时间】:2010-12-20 13:13:49
【问题描述】:

在使用 ADO.NET 时(也许我错了,我不知道它叫什么)我注意到我只能通过连接开始事务,并且命令似乎有 command.Transaction 可以让我获取事务数据但没有自己开始交易?实际上,在查看时我在 System.Data.SQLite 中看到了这个

// Summary:
    //     The transaction associated with this command. SQLite only supports one transaction
    //     per connection, so this property forwards to the command's underlying connection.
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public SQLiteTransaction Transaction { get; set; }

那么 SQLite 只支持一个事务周期?我尝试打开另一个连接,但随后我的事务引发了关于数据库被锁定的异常。所以我不能同时有一个以上的连接?

【问题讨论】:

    标签: c# .net sqlite concurrency transactions


    【解决方案1】:

    在 1 个事务中,您只能读取/写入 1 个连接,直到事务完成。因此,如果您执行跨越多个 sql 语句的业务事务,则必须传递连接对象,如下所示:

    public class TimeTableService
        {
            ITimeTableDataProvider _provider = new TimeTableDataProvider();
    
            public void CreateLessonPlanner(WizardData wizardData)
            {
                using (var con = _provider.GetConnection())
                using (var trans = new TransactionScope())
                {
                    con.Open();
    
                    var weekListA = new List<Week>();
                    var weekListB = new List<Week>();
    
                    LessonPlannerCreator.CreateLessonPlanner(weekListA, weekListB, wizardData);
    
                    _provider.DeleteLessonPlanner(wizardData.StartDate, con);
    
                    _provider.CreateLessonPlanner(weekListA, con);
                    _provider.CreateLessonPlanner(weekListB, con);
    
                    _provider.DeleteTimeTable(TimeTable.WeekType.A, con);
                    _provider.StoreTimeTable(wizardData.LessonsWeekA.ToList<TimeTable>(), TimeTable.WeekType.A, con);
    
                    _provider.DeleteTimeTable(TimeTable.WeekType.B, con);
                    _provider.StoreTimeTable(wizardData.LessonsWeekB.ToList<TimeTable>(), TimeTable.WeekType.B, con);
    
                    trans.Complete();
                }
            }
        }
    

    连接和事务处理资源由 using 语句自动释放/关闭。

    然后在每个 dataprovider 方法中执行

    using(var cmd = new SQLiteCommand("MyStatement",con)
    {
       // Create params + ExecuteNonQuery
    }
    

    TransactionScope 类是 .NET 3.5 中的新类,如果发生异常,它会自动进行回滚。易于处理...

    【讨论】:

      【解决方案2】:

      每个连接一个事务,是的,但它可以有多个连接(每个都有自己的活动事务)。

      更新:很有趣。我不知道共享缓存模式。如果您的连接使用该模式,则只有一个事务可用于使用相同共享缓存的所有连接。见SQLite shared-cache mode

      【讨论】:

      • 这并不完全正确。共享缓存模式不影响事务数。关闭共享缓存后,每个数据库连接都必须以独占方式锁定数据库文件才能写入。所以只有一个写入事务可用于所有连接。但是,在共享缓存模式下,进程内所有线程的锁定是在每个表的基础上完成的。在任一模式下,读取都可以并行完成。
      【解决方案3】:

      我不确定是否有多个连接,这可能与连接锁定文件这一事实有关,因为 SQLite 是基于文件的数据库而不是基于服务器的数据库(在基于服务器的数据库上,服务器保持所有文件锁定并处理并发连接)。

      您一次只能打开一个交易。这应该是直观的,因为在您开始事务之后发生的所有事情都在该事务中,直到rollbackcommit。然后你可以开始一个新的。 SQLite 要求所有命令都在一个事务中,所以如果你不手动打开一个新命令,它会为你这样做。

      如果您担心嵌套事务,可以使用savepoint 伪造它们。 Documentation

      【讨论】:

        猜你喜欢
        • 2013-10-28
        • 1970-01-01
        • 2018-04-11
        • 2015-08-04
        • 1970-01-01
        • 1970-01-01
        • 2016-03-17
        • 2012-02-18
        • 1970-01-01
        相关资源
        最近更新 更多