.net中的交易
在C#.Net 2.0中执行事务的最佳做法是什么? 什么是应该使用的类? 有什么缺陷等待所有提交和回滚的东西。 我刚刚开始一个项目,在将数据插入数据库时,可能需要执行一些事务。 任何有关交易的基本内容的反应或链接都是受欢迎的。
有两种主要的交易types; 连接交易和环境交易。 一个连接事务(如SqlTransaction)直接绑定到数据库连接(如SqlConnection),这意味着你必须保持传递连接 – 确定在某些情况下,但不允许“创build/使用/释放”用法,并且不允许跨数据库工作。 一个例子(格式化为空格):
using (IDbTransaction tran = conn.BeginTransaction()) { try { // your code tran.Commit(); } catch { tran.Rollback(); throw; } }
不要太乱,但只限于我们的连接“康恩”。 如果我们想用不同的方法来调用,我们现在需要传递“conn”。
另一种select是环境交易; 在.NET 2.0中, TransactionScope对象(System.Transactions.dll)允许在一系列操作上使用(适当的提供者将自动login环境事务)。 这可以很容易地适应现有的(非事务性的)代码,并且可以与多个提供者交谈(尽pipe如果你与多个提供者交谈,DTC将会涉及)。
例如:
using(TransactionScope tran = new TransactionScope()) { CallAMethodThatDoesSomeWork(); CallAMethodThatDoesSomeMoreWork(); tran.Complete(); }
请注意,这两个方法可以处理自己的连接(打开/使用/closures/处置),但是他们将默默地成为环境事务的一部分,而不需要我们传递任何东西。
如果你的代码错误,Dispose()将会被调用而没有Complete(),所以它会被回滚。 预期的嵌套等支持,虽然你不能回滚一个内部交易,但完成外部交易:如果有人不高兴,交易被中止。
TransactionScope的另一个优点是它不与数据库绑定。 任何感知交易的提供者都可以使用它。 WCF,例如。 或者甚至有一些与TransactionScope兼容的对象模型(即具有回滚function的.NET类 – 也许比纪念更容易,尽pipe我自己从来没有使用过这种方法)。
总而言之,这是一个非常非常有用的对象。
一些注意事项:
- 在SQL Server 2000上,TransactionScope将立即转到DTC; 这在SQL Server 2005及更高版本中得到了修复,直到与2个源等进行通信时,它才能使用LTM(开销less得多)。
- 有一个小故障 ,这意味着你可能需要调整你的连接string
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; } } } }
您也可以将事务包装到自己的存储过程中,并以这种方式进行处理,而不是在C#中进行事务处理。
如果你只是需要它的数据库相关的东西,一些OR映射器(例如NHibernate的)支持默认情况下开箱即用。
这也取决于你需要什么。 对于基本的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 }
任何失败都会popup你正在using
的事务,事务将总是提交或回滚(取决于你所要做的事情)。 我们面临的最大问题是确保它始终承诺。 使用确保交易的范围是有限的。