.net 中的事务

在 C# .Net 2.0 中进行事务处理的最佳实践是什么。应该使用哪些类?需要注意的陷阱是什么等等。所有提交和回滚的东西。我刚刚开始一个项目,我可能需要做一些事务,同时插入数据库的数据。任何有关交易的基本信息的回复或链接都是受欢迎的。

193307 次浏览

如果你只是需要数据库相关的东西,一些 OR 映射器(例如 NHibernate)支持每个默认框开箱即用的 Transactinos。

有两种主要的事务类型: 连接事务和环境事务。连接事务(如 SqlTransaction)直接绑定到数据库连接(如 SqlConnection) ,这意味着您必须不断传递连接——在某些情况下是可以的,但是不允许“创建/使用/发布”使用,并且不允许跨数据库工作。示例(按空格格式设置) :

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

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

另一种方法是环境事务; new in。NET 2.0,TransactionScope 事务范围对象(System。Dll)允许在一系列操作中使用(合适的提供程序将自动在环境事务中登记)。这使得修改现有(非事务性)代码和与多个提供程序通信变得容易(尽管如果与多个提供程序通信,DTC 将参与其中)。

例如:

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

请注意,这两个方法可以处理它们自己的连接(open/use/close/pose) ,但是它们将静默地成为环境事务的一部分,而不需要我们传入任何内容。

如果您的代码出错,Dispose ()将在不使用 Complete ()的情况下被调用,因此它将被回滚。支持预期的嵌套等,尽管您不能回滚内部事务,但是您可以完成外部事务: 如果任何人不满意,事务将中止。

TransactionScope 的另一个优点是它不仅与数据库绑定; 任何事务感知提供程序都可以使用它。比如周转基金。甚至还有一些与 TransactionScope 兼容的对象模型(即。NET 类具有回滚功能——可能比记忆体更容易,尽管我自己从未使用过这种方法)。

总之,这是个非常非常有用的东西。

一些警告:

  • 在 SQL Server 2000上,TransactionScope 将立即转到 DTC; 这在 SQL Server 2005及以上版本中是固定的,它可以使用 LTM (开销要小得多) ,直到您与2个源交谈,当它升级到 DTC 时。
  • 有一个 故障,这意味着您可能需要调整您的连接字符串

这也取决于你需要什么。对于基本的 SQL 事务,您可以尝试在代码中使用 BEGINTRANS 和 COMMITTRANS 来执行 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中弹出,事务将始终提交或回滚(取决于您告诉它做什么)。我们面临的最大问题是确保它始终致力于。这种使用确保了事务的范围是有限的。

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

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;


}
}
}




}