【问题标题】:Why does this TransactionScope not block subsequent requests until the first request is done?为什么这个 TransactionScope 在第一个请求完成之前不会阻塞后续请求?
【发布时间】:2014-10-13 13:32:47
【问题描述】:

我已经研究了两天的交易,也许我在收集了这么多信息后遗漏了一些明显的东西。这里的目标是阻止同时请求。如果condition 为真,则插入数据,之后condition 将为假。同时请求都会在插入数据之前检查condition,然后都会尝试插入数据。

public async Task<ActionResult> Foo(Guid ID)
{
    Debug.WriteLine("entering transaction scope");

    using (var transaction = new TransactionScope(
        TransactionScopeOption.Required,
        new TransactionOptions() { IsolationLevel = IsolationLevel.Serializable },
        TransactionScopeAsyncFlowOption.Enabled
        ))
    {
        Debug.WriteLine("entered transaction scope");

        var context = new DbContext();

        Debug.WriteLine("querying");
        var foo = context.Foos.FirstOrDefault(/* condition */);
        Debug.WriteLine("done querying");

        context.Foos.Add(new Foo());

        /* async work here */

        Debug.WriteLine("saving");
        context.SaveChanges();
        Debug.WriteLine("saved");
        Debug.WriteLine("exiting transaction scope");
        transaction.Complete();
        Debug.WriteLine("exited transaction scope");

        return View();
    }
}

这是使用 Fiddler 一次执行两个请求时的调试输出:

进入交易范围 进入交易范围 查询 完成查询 进入交易范围 进入交易范围 查询 完成查询 保存 保存 已保存 System.Data.dll 中出现“System.Data.SqlClient.SqlException”类型的第一次机会异常 退出交易范围 退出交易范围

这是我对代码应该如何工作的理解:

很明显,它并没有像我想要的那样工作。使用TransactionScope 可以实现我的目标吗?还是我必须升级到 EF 6?

【问题讨论】:

    标签: c# asp.net-mvc entity-framework entity-framework-5 transactionscope


    【解决方案1】:

    序列化并不能解决旧的“检查然后插入”问题。两个可序列化事务可以同时评估条件,得出它们必须插入的结论,然后都尝试插入,但只有一个失败,一个成功。这是因为所有读取在可序列化隔离下都相互兼容(实际上它们在所有隔离级别下都是兼容的)。

    关于如何解决这个问题有很多学派。有些人建议使用MERGE。有些人建议在检查查询中使用锁提示来获取 X 或 U 锁。我个人建议始终 INSERT 并优雅地恢复重复键违规。 确实工作的另一种方法是使用显式app locks

    EF 或 System.Transactions 确实只会给问题添加噪音。这基本上是一个后端 SQL 问题。至于如何在线程之间流动事务范围的问题,请参阅Get TransactionScope to work with async / await(显然,您已经知道这一点,从阅读 OP...我没有在第一次阅读时注册)。您将需要它来让您的异步代码在适当的上下文中登记,但阻塞/锁定仍然是基本的后端问题。

    【讨论】:

    • 那我从根本上误解了how transaction isolation levels work。事后看来,优雅地恢复是最简单的解决方案,但我在寻找此问题的解决方案时很早就发现了事务隔离级别,这看起来是正确的方法。
    • 啊,我明白了。在提交第一个事务之前,第二个事务不能插入新数据,但第二个事务仍然可以读取数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    相关资源
    最近更新 更多