TransactionScope 与 SQLite 内存数据库和 NHibernate

Posted

技术标签:

【中文标题】TransactionScope 与 SQLite 内存数据库和 NHibernate【英文标题】:TransactionScope with SQLite in-memory database and NHibernate 【发布时间】:2011-03-20 15:37:32 【问题描述】:

我遇到了使用TransactionScope 时事务不回滚的问题。

我们将 NHibernate 与内存中的 SQLite 数据库一起使用,因此在应用程序的整个生命周期内,我们只能使用一个数据库连接(在这种情况下,是一些单元测试)。

using (var ts = new TransactionScope(TransactionScopeOption.Required, 
                                     TimeSpan.Zero))

    using (var transaction = _repository.BeginTransaction())
    
        _repository.Save(entity);
        transaction.Commit();
    
    // ts.Complete(); <- commented Complete call still commits transaction

即使我删除了 NHibernate 的内部嵌套事务,所以代码如下所示,事务仍然被提交。

using (var ts = new TransactionScope(TransactionScopeOption.Required, 
                                     TimeSpan.Zero))
       
    _repository.Save(entity);        
 // no Complete(), but the transaction still commits 

它是否期望在TransactionScope 块内有一个新打开的 SQLite 连接以便将其加入事务?

同样,我无法为其提供新连接,因为这会清除数据库。

使用 NHibernate 3.0 和 SQLite 1.0.66.0,在撰写本文时都是最新版本。

注意:在 NHibernate ITransaction 对象上使用 transaction.Rollback() 可以正确回滚事务,只是 TransactionScope 支持似乎不起作用。

【问题讨论】:

SQLite(及其驱动程序)是否支持分布式事务,还是明确知道 TransactionScope? @diego:是的,根据 SQLite ADO.NET 提供者论坛上的帖子,TransactionScope 已经支持几年了。 “自动分布式事务登记”也是他们主页上注明的功能之一。 如果在范围结束后检查,数据是否持久化? 【参考方案1】:

我想我可能已经找到了原因。如果连接不是从 TransactionScope 块内部打开的,则不会在事务中登记。

这里有一些信息: http://msdn.microsoft.com/en-us/library/aa720033(v=vs.71).aspx

解决方案:

我的存储库中已经有一个.BeginTransaction() 方法,所以我想我应该手动在环境事务中登记连接。

这是我最终得到的代码:

    /// <summary>
    /// Begins an explicit transaction.
    /// </summary>
    /// <returns></returns>
    public ITransaction BeginTransaction()
    
        if (System.Transactions.Transaction.Current != null)
        
            ((DbConnection) Session.Connection).EnlistTransaction(System.Transactions.Transaction.Current);
        
        return Session.BeginTransaction();
    

这是我的使用方法:

  using (var ts = new TransactionScope(TransactionScopeOption.Required, TimeSpan.Zero))
  using (var transaction = repository.BeginTransaction())
  
       repository.Save(entity);
       transaction.Commit(); // nhibernate transaction is commited
        // ts.Complete(); // TransactionScope is not commited
   // transaction is correctly rolled back now

【讨论】:

以上是关于TransactionScope 与 SQLite 内存数据库和 NHibernate的主要内容,如果未能解决你的问题,请参考以下文章

内存中的 Sqlite - TransactionScope - 已检测到环境事务

将 TransactionScope 与实体框架 6 一起使用

TransactionScope不能与linux上的async / await方法一起使用

使用TransactionScope做分布式事务协调

C#分布式事务解决方案-TransactionScope

错误 - 具有多个数据库连接的 LINQ/TransactionScope