2015-04-08 140 views
1

我环顾四周,但找不到合适的(或对我来说满意的)如何解决我们遇到的问题。Dapper + Oracle + TransactionScope =交易已中止

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

在事务范围下执行命令时,通过引发的TransactionAbortedException,我得到一个错误“Transaction has aborted”。

观察到的行为:当且仅当交易完成

1)TransactionAbortedException被抛出并且TransactionScope的设置。抛出异常时的时间点是在处理期间。

2)尽管有例外,交易概念实际上起作用!在完成()被调用后,更改被提交到数据库中。

下面是代码片段。

// 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() 

=========================================== =======================
UPDATE(09-Apr-15)

我改变了我的方法,现在使用以下模式甲骨文。我们的代码处理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(); 
     } 
    } 
} 

回答

0

我正在诉诸使用BeginTransaction()作为最后的方法(请参阅我的原始文章中的更新)。我已阅读更多关于为什么TransactionScope()失败。

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

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

0

首先,异常被记录为可能的:

到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(); 
} 
+0

感谢您的建议和分享该文档片段。将范围移近dbConn范围之外并没有解决问题。 – Migg

0

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

+0

即使只有一个项目,我也会遇到同样的异常。当我插入到SQL Server中时不会发生。 – Migg

+0

你能发布包括任何内部异常在内的错误的整个堆栈跟踪吗? –

+0

我会如果有什么。错误堆栈仅在方法级别,并且没有内部异常。 – Migg