【问题标题】:TransactionScope vs Transaction in LINQ to SQLTransactionScope 与 LINQ to SQL 中的事务
【发布时间】:2009-02-12 17:50:23
【问题描述】:

LINQ to SQL 中的经典事务模式有什么区别,比如:

using(var context = Domain.Instance.GetContext())
{
    try
    {
        context.Connection.Open();
        context.Transaction = context.Connection.BeginTransaction();
        /*code*/
        context.Transaction.Commit();
    }
    catch
    {
        context.Transaction.Rollback();
    }         
}

与 TransactionScope 对象相比

using (var context = Domain.Instance.GetContext())
using (var scope = new TransactionScope())
{
    try
    {
        /*code*/
        scope.Complete();
    }
    catch
    {
    }
}

【问题讨论】:

    标签: c# linq linq-to-sql transactions


    【解决方案1】:

    应该注意的是,当使用 TransactionScope 时,您不需要 try/catch 构造。您只需在范围上调用 Complete 即可在退出范围时提交事务。

    话虽如此,TransactionScope 通常是更好的选择,因为它允许您嵌套调用可能需要事务的其他方法,而无需传递事务状态。

    DbConnection 对象上调用BeginTransaction 时,如果您想在同一个事务中执行其他操作,但使用不同的方法,则必须传递该事务对象。

    使用TransactionScope,只要范围存在,它就会处理在线程上以当前Transaction 注册的所有内容,从而使您的代码更简洁,更易于维护。

    除此之外,您还可以使用其他可以参与事务的资源,而不仅仅是与数据库的连接。

    需要注意的是,在需要充分利用连接和数据库操作的情况下,您可能不想使用TransactionScope;即使针对单个数据库,您也有可能使用分布式事务协调器并将事务转换为分布式事务(即使对于单个数据库连接)。

    在这些情况下,在混淆您的设计时,您可能需要考虑传递特定于连接的事务。

    或者,如果您知道您将始终如一地使用一个资源(并且在同一个线程上),您可能想要创建一个对您的连接/事务进行引用计数的类。

    您将创建一个在构造时创建资源/增加计数的类。它还将实现IDisposable(当计数为零时,您将递减/释放/提交/中止),并将计数存储在应用了ThreadStaticAttribute 的变量中。

    这允许您将事务管理与逻辑代码分开,并且仍然相当有效地保持单一资源(而不是升级为分布式事务)。

    【讨论】:

    • 如果我对事务使用单一连接,那不是一样的吗?我的意思是你避免分布式事务..
    • @Parhs 取决于您是否在具有单个数据库连接的事务中登记了其他事务资源。
    • 我的提供者不允许嵌套事务(数据库),所以还有问题吗?
    • @Parhs 这与数据库提供商无关,但您可以拥有事务文件系统、事务 Web 服务等。如果这些内容包含在具有单个数据库连接的事务中,则 DTC步入。
    【解决方案2】:

    Linq2SQL 将使用隐式事务。如果您的所有更新都在一次提交中完成,您可能不需要自己处理事务。

    来自文档(重点是我的):

    当您调用 SubmitChanges 时,LINQ to SQL 会检查调用是否在事务范围内,或者事务属性 (IDbTransaction) 是否设置为用户启动的本地事务。 如果没有找到事务,LINQ to SQL 会启动一个本地事务 (IDbTransaction) 并使用它来执行生成的 SQL 命令。 当所有 SQL 命令都成功完成后,LINQ to SQL 会提交本地事务并执行返回。

    【讨论】:

    • 如果您需要提交具有循环属性的东西(常见),您遇到了 LINQ to SQL 中的一个错误,该错误要求您删除每个 2-way 引用的一部分,提交,修复 2-way参考,然后再次提交。您需要将所有这些都包含在您自己的事务中才能执行此操作。这是一个普遍的需求,所以“别担心”不是最好的答案。
    【解决方案3】:

    一个很大的不同(从惨痛的教训中吸取了教训)——TransactionScope 使用 MS DTC 进行事务管理。

    如果您的应用程序只需要管理数据库事务,并且不涉及服务或远程调用,则可以通过使用数据库原生事务 (DbTransactions) 来跳过与 MS DTC 相关的潜在问题。

    【讨论】:

    • 我也刚刚学会了这一点!但很高兴用 msdtc 解决了一场噩梦
    • Mayank(或其他任何人)。我在事务和单元测试方面遇到了更多问题,你能帮我解决这个stackoverflow.com/questions/9636533/… 吗?
    • 这并非总是如此。 TransactionScope 将根据需要从内核事务升级到 DTC 事务。然而,这一切都对你隐藏。重要的一点是它不会总是这样做,而是根据需要
    • 如果您使用相同的数据上下文,则不会。
    【解决方案4】:

    TransactionScope 为所有资源管理器(SQL 服务器、活动目录、文件系统……)提供统一管理。此外,可以编写自己的资源管理器:检测事务范围的代码,加入它并像 SQL 服务器一样工作:像事务的其他参与者一样提交或恢复更改。我相信 TransactionScope 是主流,忘记了 MS SQL 原生事务,直到陷入巨大的陷阱: Windows Server 2008 WEB 版附带受限的分布式事务协调器服务,事务范围仅适用于单台计算机。 如果 IIS 和 SQL 服务器安装在不同的计算机上,您的 ASP.NET 应用程序将在此系统上失败。考虑到大多数公共域提供商提供的 Windows Server WEB 版本和 SQL Server 位于不同的服务器上。这意味着,您必须使用显式事务管理来处理本机事务……

    【讨论】:

      【解决方案5】:

      我相信它们与 TransactionScope 类将与 ADO.NET 底层连接接口以创建和提交或回滚事务的基本相同。刚刚创建 TransactionScope 类是为了使使用 ADO.NET 持久性更清晰。

      编辑:澄清我关于casperOne's addition的声明,它将创建事务的TransactionScope,然后连接将看到由TransactionScope创建的事务并使用它,因为它可用给它。

      【讨论】:

      • @Christ Marisic:恰恰相反。该连接查找当前线程的事务是否存在,该线程将由 TransactionScope 创建。如果有,那么它会加入事务。然后协调器将告诉连接提交或回滚。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多