2015-04-08 141 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