【问题标题】:SQLite with TransactionScope and Increment Identity Generator带有 TransactionScope 和增量身份生成器的 SQLite
【发布时间】:2010-10-29 07:42:58
【问题描述】:

当尝试将 SQLite 与 System.Transactions TransactionScope 与身份生成器作为增量一起使用时,我注意到当 NHibernate 尝试检索下一个身份号时,我遇到了异常(下面连同代码一起给出)。

这似乎是因为新的 SQLite 连接正在对当前事务进行自动登记。据我所知,SQLite 只支持单写事务,但应该支持多读,所以我很惊讶我得到一个读操作的数据库锁定异常。有没有人以这种方式使用带有事务范围的 SQLite。

如果我使用 NHibernate Transaction 而不是 TransactionScope,则相同的代码可以正常工作

代码块:

           using (var scope = new TransactionScope()) 
            { 
                var userRepository = 
container.GetInstance<IUserRepository>(); 
                var user = new User(); 
                userRepository.SaveOrUpdate(user); 
                scope.Complete(); 
            } 

例外:

19:34:19,126 ERROR [   7] IncrementGenerator [(null)]- could not get 
increment value 
System.Data.SQLite.SQLiteException: The database file is locked 
database is locked 
   at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) 
   at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() 
   at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection 
connection, Boolean deferredLock) 
   at System.Data.SQLite.SQLiteConnection.BeginTransaction(Boolean 
deferredLock) 
   at System.Data.SQLite.SQLiteConnection.BeginTransaction() 
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, 
Transaction scope) 
   at 
System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction 
transaction) 
   at System.Data.SQLite.SQLiteConnection.Open() 
   at NHibernate.Connection.DriverConnectionProvider.GetConnection() 
   at NHibernate.Id.IncrementGenerator.GetNext(ISessionImplementor 
session) 
19:34:20,063 ERROR [   7] ADOExceptionReporter [(null)]- The database 
file is locked 
database is locked

【问题讨论】:

    标签: nhibernate sqlite transactionscope


    【解决方案1】:

    这里有两件事在起作用。

    正如您所提到的,System.Data.SQLite 将自动加入分布式事务。默认开启,添加Enlist=no即可关闭。

    第二个是System.Data.SQLite默认创建带有自动写锁的事务。这是基于这样的假设:如果一个事务启动,就会完成写入。这可以通过使用Serializable.ReadCommitted 启动事务来覆盖。

    也可以使用DefaultIsolationLevel 键在连接字符串中指定默认值。有效值为 ReadCommittedSerializable。 SQLite 不支持其他隔离级别。 ReadCommitted 延迟写锁,而Serializable 立即获得写锁。

    未指定将使用连接字符串中指定的默认隔离级别。如果连接字符串中没有指定隔离级别,则使用 Serializable。可序列化事务是默认设置。在这种模式下,引擎会立即锁定数据库,并且没有其他线程可以开始事务。其他线程可以从数据库中读取,但不能写入。

    使用 ReadCommitted 隔离级别,锁会根据需要延迟和提升。多个线程可以在 ReadCommitted 模式下启动事务,但如果一个线程尝试提交事务,而另一个线程具有 ReadCommitted 锁,则可能会超时或导致两个线程死锁,直到两个线程的 CommandTimeout 都达到。

    【讨论】:

    • 我确实查看了 Enlist 选项,但我无法将其关闭,因为我需要明确地对其进行登记,并且我将无权访问连接对象。您能否指定 ConnectionString 中用于指定默认事务隔离级别的键是什么。 MSDN 文档说 TranactionScope 的默认隔离级别是 ReadCommitted
    • @Dinesh Manne,我编辑了答案以添加有关默认隔离级别的更多信息。我不确定您具体指的是哪些关于 MSDN 和 TransactionScope 的文档,但是 SQLite 不像其他数据库那样支持不同类型的事务隔离级别,它重用隔离级别用于稍微不同的目的(用于其他数据库不一定有)。 SQLite 以前不这样做,它过去只是在 SQLiteConnection 上有一个自定义重载,但是如果不直接引用 SQLiteConnection 类就不可能使用延迟锁。
    • 当一个线程尝试启动一个事务而另一个事务处于活动状态时,我遇到了“数据库文件被锁定”异常的问题。最好将任何事务放在一个锁中{},否则会导致其他问题吗?
    猜你喜欢
    • 1970-01-01
    • 2011-05-31
    • 2019-06-07
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 2019-11-26
    相关资源
    最近更新 更多