【问题标题】:Does TransactionScope work with pre-existing connections?TransactionScope 是否适用于预先存在的连接?
【发布时间】:2012-02-13 09:11:58
【问题描述】:

我有这样的代码:

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");   
}

在 db 函数内部会发生这样的事情:

private void some_db_functions()
{
    using (TransactionScope scope = new TransactionScope())
    {
       //some processing on db
       scope.Complete();
    }
}

应该是数据库事务出现问题,比如函数插入或更新出错;到目前为止已完成的所有事务都会回滚。但它不是那样工作的;尽管它抛出了一个异常并且父函数中的scope.Complete() 永远不会被触发,但仍然没有回滚。

问题出在哪里?

【问题讨论】:

  • 你只是不需要使用 scope.Complete() ,在 using 语句中使用 Transaction 范围可以处理所有事情。
  • 您的数据库方法是打开连接还是使用现有连接?
  • 它没有。即使没有 scope.Complete() 它也不能正常工作。
  • 它们都使用相同的连接,之前声明过。
  • @Flowerking 不,您在成功场景结束时明确需要Complete()。如果你不调用Complete(),它总是在Dispose()期间回滚(通常通过using

标签: c# transactionscope


【解决方案1】:

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

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

在事务范围内打开一个连接。

或者,如果连接已经打开,调用 EnlistTransaction 方法 在连接对象上。

Ref.

这将征用一个现有的连接:

connection.EnlistTransaction(Transaction.Current)

【讨论】:

    【解决方案2】:

    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();
        // ...
    }
    

    【讨论】:

    • @Mitch 鉴于我们的帖子之间有大约 30 秒的间隔,我很确定我们是在并行输入的。是的,我们同意。
    • 那么那些 scope.Complete()s 是不是每个函数都需要它们呢?
    • @Siyavash 嗯?每笔交易都需要它们一次
    • @Siyavash 这取决于您是否希望单独调用这些子方法。在最简单的情况下,您可以只使用封装(最外层)事务。但是如果你确实有内部事务,那么是的:它们都需要在被处理之前完成,否则它们会立即注定最外层事务。
    • @Siyavash 它到底是在哪里说的?如果你指的是例子:那是为了说明你可以嵌套事务,如果你这样做:本质上最外面的事务控制“提交”,任何失败控制“中止”。您不是必须在多个级别上使用事务范围,而且TransactionScope 最有用的特性之一是它自动应用于嵌套代码而无需明确实施与交易有关的任何更改。
    猜你喜欢
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 2020-06-03
    • 1970-01-01
    • 2012-08-16
    • 2015-07-06
    相关资源
    最近更新 更多