2011-03-04 216 views
2

我目前使用微軟企業庫5.0,我想知道,如果下面的代碼是處理事務的接受的方式回滾多個事務。企業庫:

我已經簡化場景一點,但本質上,我想在同一事務內執行不同的數據庫多個插入。

如果兩個刀片的失敗,所有的交易應該被回滾。

我已經看了TransactionScope,但我想知道如果我能沒有它管理。

public void InsertStuff_AcrossDbs() 
{ 
    //Create a ref to 2 different Db's on the same server 
    Database db_a = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_a"); 
    Database db_b = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_b"); 

    //Create Connections for the 2 db's 
    using (DbConnection connection_db_a = db_a.CreateConnection()) 
    using (DbConnection connection_db_b = db_b.CreateConnection()) 
    { 
     //Create DbTransactions for the 2 db's 
     DbTransaction transaction_dbA = connection_db_a.BeginTransaction(); 
     DbTransaction transaction_dbB = connection_db_b.BeginTransaction(); 

     try 
     { 
      //Insert into DbA.Person and get the PK 
      DbCommand dbCmd_dbA_insert = db_a.GetSqlStringCommand("Insert INTO Person(Name,Age)Values('test',23); SET @pkReturnId= SCOPE_IDENTITY() "); 
      db_a.AddOutParameter(dbCmd_dbA_insert, "pkReturnId", DbType.Int32, 0); 
      db_a.ExecuteNonQuery(dbCmd_dbA_insert, transaction_dbA); 
      int personID = Convert.ToInt32(db_a.GetParameterValue(dbCmd_dbA_insert, "@pkReturnId")); 

      //Insert 'personId' into dbB.Employee (a different table in a different db) 
      DbCommand dbCmd_dbB_delete = db_a.GetSqlStringCommand("Insert INTO Employee(personId) VALUES(" + personID + ")"); 
      db_a.ExecuteNonQuery(dbCmd_dbB_delete, transaction_dbB); 

      //try to commit both transactions 
      transaction_dbA.Commit(); 
      transaction_dbB.Commit(); 
     } 
     catch (Exception ex) 
     { 
      //If either transactions fails, roll back both 
      try 
      { 
       transaction_dbA.Rollback(); 
      } 
      catch { } 

      try 
      { 
       transaction_dbB.Rollback(); 
      } 
      catch { } 

      throw ex; 
     } 
     finally 
     { 
      connection_db_a.Close(); 
      connection_db_b.Close(); 
     } 

    } 

} 

這段代碼被認爲OK,或者是否會有場景中不是所有的交易都將被回滾,如果他們中的一個應該拋出一個錯誤?

回答

3

你的代碼是不是OK。有兩種數據庫不一致的情況。

在你的代碼創建兩個本地交易:一個在數據庫中的一個在數據庫B,這是不是你想要的,因爲你想同時操作,以保持一致性一個事務中發生。要做到這一點,你需要使用分佈式事務,正如你所提到的,TransactionScope是做這件事的最好方法。它也將使代碼更具可讀性。

例如

Database db_a = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_a"); 
Database db_b = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_b"); 

using (TransactionScope scope = new TransactionScope()) 
{ 
    using (DbConnection connA = db_a.CreateConnection()) 
    { 
     // ... 
    } 

    using (DbConnection connB = db_b.CreateConnection()) 
    { 
     // ... 
    } 

    scope.Complete(); 
} 

我知道你的代碼是一個簡單的場景,所以我不知道如果這些應用到實際的代碼,但這裏有一些其他意見:

DbCommand dbCmd_dbB_delete = 
    db_a.GetSqlStringCommand("Insert INTO Employee(personId) VALUES(" + personID + ")"); 

動態SQL字符串應該是可以避免的。由於數據庫執行計劃不會被其他具有不同參數的請求重複使用,因此它們容易受到SQL注入攻擊以及性能下降的影響。

finally 
{ 
    connection_db_a.Close(); 
    connection_db_b.Close(); 
} 

你並不需要手動關閉連接,因爲你是通過你的使用語句和關閉和處置在功能上等同配置的連接。