2013-02-12 84 views
2

我正在开发一个由别人开发的项目。在节目中,它确实是这样的:手动区分TransactionScope和Rollback事务?

reportConnection = new SqlConnection(sConnStr); 
reportConnection.Open(); 
try 
{ 
    using (SqlTransaction trans = reportConnection.BeginTransaction(IsolationLevel.ReadUncommitted))      

    { 
     ...... 
     using (SqlCommand cmd = new SqlCommand(sSQL, reportConnection, trans)) 
     { 
      .... 
     } 
     trans.Commit(); 
    } 
} 
catch (Exception ex) 
{ 
    Logger .... 
} 
fianlly 
{ 
    if (reportConnection != null) 
    { 
     ((IDisposable)reportConnection).Dispose(); 
    } 

} 

我可以看到的问题是,如果在使用块中的错误不会回滚事务。所以,这里是第一个问题:如果有错误,trans将不会被提交(也不回滚),但连接将被丢弃(trans不会被丢弃)。在这种情况下,它会产生什么副作用?它会创建一个打开的孤立连接/事务吗?因此,会造成僵局?

我做了一些搜索,似乎最好是使用(如下微软代码)TransactionScope的方式做到这一点:

try 
{ 
    // Create the TransactionScope to execute the commands, guaranteeing 
    // that both commands can commit or roll back as a single unit of work. 
    using (TransactionScope scope = new TransactionScope()) 
    { 
     using (SqlConnection connection1 = new SqlConnection(connectString1)) 
     { 
      // Opening the connection automatically enlists it in the 
      // TransactionScope as a lightweight transaction. 
      connection1.Open(); 

      // Create the SqlCommand object and execute the first command. 
      SqlCommand command1 = new SqlCommand(commandText1, connection1); 
      returnValue = command1.ExecuteNonQuery(); 
      writer.WriteLine("Rows to be affected by command1: {0}", returnValue); 

      // If you get here, this means that command1 succeeded. By nesting 
      // the using block for connection2 inside that of connection1, you 
      // conserve server and network resources as connection2 is opened 
      // only when there is a chance that the transaction can commit.  
      using (SqlConnection connection2 = new SqlConnection(connectString2)) 
      { 
       // The transaction is escalated to a full distributed 
       // transaction when connection2 is opened. 
       connection2.Open(); 

       // Execute the second command in the second database. 
       returnValue = 0; 
       SqlCommand command2 = new SqlCommand(commandText2, connection2); 
       returnValue = command2.ExecuteNonQuery(); 
       writer.WriteLine("Rows to be affected by command2: {0}", returnValue); 
      } 
     } 

     // The Complete method commits the transaction. If an exception has been thrown, 
     // Complete is not called and the transaction is rolled back. 
     scope.Complete(); 

    } 

} 
catch (TransactionAbortedException ex) 
{ 
    writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message); 
} 
catch (ApplicationException ex) 
{ 
    writer.WriteLine("ApplicationException Message: {0}", ex.Message); 
} 

我的第二个问题是:如果我手工做的像下面。使用transactionscope的优点?他们真的是一样的吗?

reportConnection = new SqlConnection(sConnStr); 
reportConnection.Open(); 
try 
{ 
    using (SqlTransaction trans = reportConnection.BeginTransaction(IsolationLevel.ReadUncommitted))      

    { 
     try 
     { 
      ...... 
      using (SqlCommand cmd = new SqlCommand(sSQL, reportConnection, trans)) 
      { 
       .... 
      } 
      trans.Commit(); 
     } 
     catch 
     { 
      try 
      { 
       // incase rollback has error 
       trans.Rollback(); 
      } 
      catch 
      { 
      } 
     } 
    } 
} 
catch (Exception ex) 
{ 
    Logger .... 
} 
fianlly 
{ 
    if (reportConnection != null) 
    { 
     ((IDisposable)reportConnection).Dispose(); 
    } 

} 

谢谢。

回答

0

这是覆盖SqlTransaction文档中:

处置应回滚事务。但是, Dispose的行为是特定于提供程序的,不应取代调用回滚。

来自http://msdn.microsoft.com/en-us/library/bf2cw321.aspx

我想这一切都取决于你对试图迫使当你认为他们可能不碎实现正常工作如何偏执。第一个代码示例绝对是最简单的,如果您的提供程序不能正常工作,它只会失败。

编辑复杂的例子 - 如果你的最后一个片段是:

try { /*...*/ 
    using (SqlCommand cmd = new SqlCommand(sSQL, reportConnection, trans)) { 
     /*...*/ } 
    trans.Commit(); 
} catch { try { trans.Rollback(); } catch {} throw; } 

try { /*...*/ 
    using (SqlCommand cmd = new SqlCommand(sSQL, reportConnection, trans)) { 
     /*...*/ } 
} catch { try { trans.Rollback(); } catch {} throw; } 
trans.Commit();