TransactionScope是否适用于预先存在的连接
本文关键字:存在 连接 是否 适用于 TransactionScope | 更新日期: 2023-09-27 18:24:11
我有一个这样的代码:
try
{
using (TransactionScope scope = new TransactionScope())
{
some_db_function();
for (i = 0; i < 10; i++)
{
some_other_db_function();
}
scope.Complete();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " all done transactions will rollback");
}
在数据库功能内部会发生这样的事情:
private void some_db_functions()
{
using (TransactionScope scope = new TransactionScope())
{
//some processing on db
scope.Complete();
}
}
应该是,如果数据库事务中有任何问题,比如在函数中插入或更新错误;到目前为止,所有已完成的事务都被回滚。但它并不是这样运作的;尽管它抛出了一个异常,并且父函数中的scope.Complete()
从未被触发,但仍然没有任何东西被回滚。
问题出在哪里?
如果打开的连接已经存在,它将不会自动登记在环境事务中。您必须明确设置它。
不支持隐式登记连接。参加事务范围,您可以执行以下操作:
打开事务范围中的连接。
或者,如果连接已经打开,则调用EnlistTransaction方法在连接对象上。
参考。
这将登记一个现有的连接:
connection.EnlistTransaction(Transaction.Current)
IIRC,在连接创建/打开时自动登记到环境事务中;如果在事务范围内创建连接,那么一切都应该是好的。但是:
它们都使用相同的连接,之前声明
如果连接存在于事务之外,则不会登记。
最佳实践是只围绕一个工作单元创建/打开连接,而不是永远创建/打开(并且:让连接池来完成它的工作)。如果你遵循这种做法,它应该会很好。因此:
这不起作用:
using(var conn = CreateAndOpenConnection()) {
// ...
using(var tran = new TransactionScope()) {
SomeOperations(conn);
tran.Complete();
}
// ...
}
这应该在哪里工作:
using(var tran = new TransactionScope()) {
// ...
using(var conn = CreateAndOpenConnection()) {
SomeOperations(conn);
}
tran.Complete();
// ...
}