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()从未被触发,但仍然没有任何东西被回滚。

问题出在哪里?

TransactionScope是否适用于预先存在的连接

如果打开的连接已经存在,它将不会自动登记在环境事务中。您必须明确设置它。

不支持隐式登记连接。参加事务范围,您可以执行以下操作:

打开事务范围中的连接。

或者,如果连接已经打开,则调用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();
    // ...
}