.net

2008-10-22 82 views
123

在C#.Net 2.0中执行事务的最佳做法是什么?什么是应该使用的类?有什么陷阱要留意等所有提交和回滚的东西。我刚刚开始一个项目,在将数据插入数据库时​​可能需要执行一些事务。任何有关交易的基本内容的反应或链接都是受欢迎的。.net

+0

这是一个很好的例子,在.NET中的事务(http://www.codeproject.com/KB/database/transactions.aspx)在codeproject上用作开始。 – 2008-10-22 06:45:13

+2

有用的http://www.codeproject.com/Articles/690136/All-About-TransactionScope – Kiquenet 2013-12-03 19:21:48

回答

235

有两种主要的交易类型;连接交易和环境交易。连接事务(如SqlTransaction)直接绑定到数据库连接(例如SqlConnection),这意味着您必须保持传递连接 - 在某些情况下可以,但不允许“创建/使用/释放”用法,并且不允许跨数据库工作。一个例子(格式化为空格):

using (IDbTransaction tran = conn.BeginTransaction()) { 
    try { 
     // your code 
     tran.Commit(); 
    } catch { 
     tran.Rollback(); 
     throw; 
    } 
} 

不是太混乱,但仅限于我们的连接“conn”。如果我们想要调用不同的方法,我们现在需要传递“conn”。

替代方案是环境交易; .NET 2.0中的新增功能,TransactionScope对象(System.Transactions.dll)允许在一系列操作中使用(适合的提供程序将自动登录环境事务)。这可以很容易地适应现有的(非事务性)代码,并且可以与多个提供商交谈(尽管如果您与多个提供商交谈,DTC将会参与其中)。

例如:这里

using(TransactionScope tran = new TransactionScope()) { 
    CallAMethodThatDoesSomeWork(); 
    CallAMethodThatDoesSomeMoreWork(); 
    tran.Complete(); 
} 

请注意,这两种方法可以处理自己的连接(开/使用/关闭/处置),但他们会悄悄地成为环境事务的一部分,无需我们不必通过任何东西。

如果你的代码错误,Dispose()将会在没有Complete()的情况下被调用,所以它会被回滚。预期的嵌套等被支持,虽然你不能回滚一个内部交易,但完成外部交易:如果有人不满意,交易将被中止。

TransactionScope的另一个优点是它不仅仅与数据库绑定在一起;任何支持事务的提供者都可以使用它。例如WCF。或者甚至有一些与TransactionScope兼容的对象模型(即具有回滚功能的.NET类 - 也许比纪念更容易,尽管我自己从未使用过这种方法)。

总而言之,这是一个非常非常有用的对象。

一些注意事项:

  • 在SQL Server 2000中,一个TransactionScope将立即转至DTC;这在SQL Server 2005及更高版本中得到了解决,它可以使用LTM(开销少得多),直到与2个源等进行通信时,它被提升为DTC。
  • 有一个glitch这意味着你可能需要调整您的连接字符串
+1

http://www.codeguru.com/columns/vb/article.php/c11067 – Kimoz 2008-10-22 06:50:55

1

如果你只是需要它的数据库相关的东西,一些OR映射器(例如NHibernate)默认情况下开箱即用支持TRANSACTINO。

0

这也取决于你所需要的。对于基本的SQL事务,您可以尝试在您的代码中使用BEGIN TRANS和COMMIT TRANS来执行TSQL事务。这是最简单的方法,但它确实有复杂性,你必须小心地正确提交(和回滚)。

我会使用类似

SQLTransaction trans = null; 
using(trans = new SqlTransaction) 
{ 
    ... 
    Do SQL stuff here passing my trans into my various SQL executers 
    ... 
    trans.Commit // May not be quite right 
} 

任何失败都会弹出你的权利了using和交易总是会提交或回滚(取决于你告诉它做什么)。我们面临的最大问题是确保它始终承诺。使用确保交易范围有限。

3

您也可以将事务包装到自己的存储过程中,并以这种方式处理它,而不是在C#中进行事务处理。

10
protected void Button1_Click(object sender, EventArgs e) 
    { 


     using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True")) 
     { 
      connection1.Open(); 

      // Start a local transaction. 
      SqlTransaction sqlTran = connection1.BeginTransaction(); 

      // Enlist a command in the current transaction. 
      SqlCommand command = connection1.CreateCommand(); 
      command.Transaction = sqlTran; 

      try 
      { 
       // Execute two separate commands. 
       command.CommandText = 
       "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')"; 
       command.ExecuteNonQuery(); 
       command.CommandText = 
       "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')"; 
       command.ExecuteNonQuery(); 

       // Commit the transaction. 
       sqlTran.Commit(); 
       Label3.Text = "Both records were written to database."; 
      } 
      catch (Exception ex) 
      { 
       // Handle the exception if the transaction fails to commit. 
       Label4.Text = ex.Message; 


       try 
       { 
        // Attempt to roll back the transaction. 
        sqlTran.Rollback(); 
       } 
       catch (Exception exRollback) 
       { 
        // Throws an InvalidOperationException if the connection 
        // is closed or the transaction has already been rolled 
        // back on the server. 
        Label5.Text = exRollback.Message; 

       } 
      } 
     } 


    }