.NET中的事务处理

152

在C# .Net 2.0中进行交易的最佳实践是什么?应该使用哪些类?需要注意什么陷阱等。所有的提交和回滚操作。我刚开始一个项目,可能需要在向数据库插入数据时执行一些事务。欢迎任何关于交易的基础知识的回应或链接。


这里有一个很好的 .NET中事务处理 的例子,可以作为一个起点。 - Mitchel Sellers
2
有用的 http://www.codeproject.com/Articles/690136/All-About-TransactionScope - Kiquenet
5个回答

281

主要有两种类型的事务:连接事务和环境事务。连接事务(例如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。 - 存在一个小故障,这意味着您可能需要调整连接字符串。

CSLA .NET 2.0 支持 TransactionScope 对象! - Binoj Antony
1
@ Eduardo - 当使用TransactionScope时,这不是一个问题,使其非常有吸引力。这些事务会嵌套,并且仅最外层提交。 - Marc Gravell
1
马克,又一次的出色解释。当你说“支持预期嵌套”时,是指在方法内定义的事务块(例如CallAMethodThatDoesSomeWork())吗?还是在外部定义的TransactionScope中也可以不需要? - Phil Cooper
@MarcGravell 我明白,但这确实使得一些事情更加复杂难以实现。谢谢。 - MeTitus
第一个代码片段中,tran.Rollback(); 这一行不是必须的吗?至少对于大多数 IDbTransaction 实现来说是这样的吗? - astef
显示剩余4条评论

13
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;

               }
           }
       }


   }

4
你也可以将事务封装在自己的存储过程中,这样可以避免在C#中进行事务处理。

1

如果你只需要它用于数据库相关的工作,一些对象关系映射器(例如NHibernate)默认支持事务。


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,并且事务将始终提交或回滚(取决于您告诉它要做什么)。我们面临的最大问题是确保它始终提交。使用确保了事务范围的限制。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接