【问题标题】:Dapper + Oracle + TransactionScope = Transaction has abortedDapper + Oracle + TransactionScope = 事务已中止
【发布时间】:2015-04-08 02:29:17
【问题描述】:

我环顾四周,但找不到合适的(或令我满意的)如何解决我们遇到的问题。

我使用 Dapper 和 ODP.NET 12 托管驱动程序。不使用 TransactionScope 时不会遇到问题。

在事务范围内执行命令时,我通过抛出的 TransactionAbortedException 收到错误“事务已中止”。

观察到的行为:

1) 当且仅当事务完成并且 TransactionScope 被释放时,才会抛出 TransactionAbortedException。抛出异常的时间点是在 dispose 期间。

2) 尽管有例外,但交易概念确实有效!调用 Complete() 后,更改将提交到数据库中。

下面是代码sn-p。

// Conn string: "Data Source=OraDB;Persist Security Info=True;User ID=userxxx;Password=passwordxxx;"   providerName="Oracle.ManagedDataAccess.Client
// Note: GetDbFactory().Create() returns a DbConnection object
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
using (var dbConn = GetDbFactory().Create())
{
    foreach (MyDTO dto in dtoList)
    {
        var tableDAO= new TableDAO(dbConn);
        MyEntity entity = new MyEntity()
        {
            Field1 = dto.Field1,
            Field2 = dto.Field2
        };
        tableDAO.AddOrUpdate(entity);
     }
     // Commit changes
     scope.Complete();
}

// This method is under the DAO class
public void AddOrUpdate(MyEntity entity)
{
    // Verify arguments
    entity.AsArgumentThrowExceptionIfNull("entity");
    // build param

    OracleDynamicParameters parameters = new OracleDynamicParameters();

    parameters.Add("P_FIELD1", entity.Field1);
    parameters.Add("P_FIELD2", entity.Field2);

    // execute SP
    dbConnection.Execute("PRC_MY_ENTITY_ADDORUPDATE", parameters, commandType: CommandType.StoredProcedure);
}//-- end AddOrUpdate()

================================================ ====================
更新(2015 年 4 月 9 日)

我已经改变了我的方法,现在对 Oracle 使用以下模式。我们的代码处理 Oracle 和 SQL Server 中的连接,所以我更希望编码模式是一致的,但在找到使用 Oracle+TransactionScope 的解决方案之前,我们将使用以下模式执行 Oracle 命令:

using (var dbConnection = dbConnFactory.Create())
{
    // Open db connection
    dbConnection.Open();
    using (var trans = dbConnection.BeginTransaction())
    {
        bool isSuccess = false;
        try
        {
             // Perform DB operations here
             trans.Commit();
             isSuccess = true;
        }
        finally
        {
             if(!isSuccess) trans.Rollback();
        }
   }
}

【问题讨论】:

    标签: c# dapper odp.net transactionscope


    【解决方案1】:

    首先,尽可能记录异常:

    对 Dispose 方法的调用标志着事务范围的结束。调用此方法后发生的异常可能不会影响事务。

    这在 TransactionScope 类 (https://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28v=vs.110%29.aspx) 的文档中。

    我注意到的另一件事是事务的完成是在连接关闭之前完成的。我会更改它以关闭连接,然后完成交易。

    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
    {
      using (var dbConn = GetDbFactory().Create())
      {
        foreach (MyDTO dto in dtoList)
        {
            var tableDAO= new TableDAO(dbConn);
            MyEntity entity = new MyEntity()
            {
                Field1 = dto.Field1,
                Field2 = dto.Field2
            };
            tableDAO.AddOrUpdate(entity);
         }
      }
         // Commit changes
      scope.Complete();
    }
    

    【讨论】:

    • 感谢您的建议和分享该文档 sn-p。将范围移到 dbConn 范围之外并没有解决问题。
    【解决方案2】:

    我认为该代码没有任何问题。但是,如果该循环运行的时间足够长,则事务将超时。下次您对数据库执行操作时,您将获得有问题的异常。我会尝试增加超时 - 超时是 TransactionScopeOption 类的一个属性。

    【讨论】:

    • 即使只有一个项目,我也会遇到同样的异常。插入 SQL Server 时不会发生。
    • 您能否发布错误的整个堆栈跟踪,包括任何内部异常?
    • 如果有什么我会的。错误堆栈仅在方法级别,没有内部异常。
    【解决方案3】:

    我将使用 BeginTransaction() 作为最终方法(请参阅我在原始帖子中的更新)。我已经阅读了有关 TransactionScope() 失败原因的更多信息。

    1) 在连接到 Oracle 10g 及更低版本 (source) 时,即使使用单个 DB 连接,ODP.Net 也会升级为分布式事务。瞧,我要连接的数据库确实是 10g。

    2) 您需要安装 Oracle MTS 服务。这是我在我的开发机器上没有设置的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-22
      • 2012-04-29
      • 2014-02-14
      • 2020-04-24
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多