TransactionScope与LINQ to SQL中的事务对比

78

在 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
    {
    }
}
5个回答

76
需要注意的是,在使用TransactionScope时,你不需要像使用try/catch那样构建代码块。只需在作用域结束时调用Complete方法即可提交事务。

但通常情况下,使用TransactionScope更为明智,因为它允许你嵌套调用其他可能需要事务的方法,而无需在方法之间传递事务状态。

当在DbConnection对象上调用BeginTransaction时,如果你想在同一事务中执行其他操作,就必须传递该事务对象,但这些操作位于不同的方法中。

使用TransactionScope时,只要存在作用域,它就会处理与当前线程上注册的当前Transaction相关的一切,使你的代码更加清洁、易于维护。

此外,你还可以使用其他可参与事务的资源,而不仅限于与数据库的连接。

需要注意的是,在需要充分利用连接和数据库操作的情况下,你可能不想使用TransactionScope;即使只针对单个数据库,也有可能会使用分布式事务协调器并将事务变成分布式事务。

在这些情况下,虽然会影响设计,但你可能需要考虑在连接上传递特定于该连接的事务。

或者,如果您知道将一直使用某个资源(并在同一个线程上使用),则可能希望创建一个引用计数您连接/事务的类。

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

这使您能够将事务管理与逻辑代码分开,并仍然相对高效地持有单一资源(而不是升级到分布式事务)。


如果我使用单个连接和事务,那不是一样的吗?我的意思是你可以避免分布式事务。 - GorillaApe
@Parhs 取决于您是否在事务中与单个数据库连接登记了其他事务资源。 - casperOne
我的提供者不允许嵌套事务(数据库),那么还有问题吗? - GorillaApe
2
@Parhs,这与数据库提供程序无关,但您可以拥有事务性文件系统、事务性 Web 服务等。如果这些事务与单个数据库连接一起包含在一个事务中,则 DTC 就会介入。 - casperOne

37

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

根据文档(我的强调):

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


10
如果你需要提交一个具有循环属性的东西(很常见),你会遇到LINQ to SQL中的一个错误,需要你移除每个二向引用的一部分,提交,修复这些二向引用,然后再次提交。你需要在自己的事务中包装所有这些步骤。由于这是一个常见需求,所以“不要担心”并不是最好的答案。 - Chris Moschini

21

一个很大的不同点(从失败中学到的教训)——TransactionScope 使用 MS DTC 进行事务管理。

如果您的应用程序只需要管理数据库事务,并且没有涉及任何服务或远程调用,那么可以通过使用数据库本地的事务(DbTransactions)来避免与 MS DTC 相关的潜在问题。


我也是以困难的方式学到这个!但很高兴通过解决msdtc的噩梦来解决问题。 - DevDave
Mayank(或其他人)。我在事务和单元测试方面遇到了更多问题,你能帮我解决一下吗?这是我的问题链接:http://stackoverflow.com/questions/9636533/mvc3-differences-between-test-environment-and-dev-application。 - DevDave
6
并非始终如此。TransactionScope会根据需要从内核事务升级到DTC事务。但这一切都对你隐藏了起来。重要的是,并非总是如此,而是根据需要处理。 - casperOne
不过,如果您使用相同的数据上下文,则不会出现此问题。 - Dasith Wijes

7
TransactionScope提供了统一的管理所有资源管理器(SQL Server,活动目录,文件系统等)的功能。此外,您可以编写自己的资源管理器:它会检测事务范围并加入其中,就像SQL Server一样工作:提交或回滚更改,就像事务的其他参与者一样。我认为TransactionScope是主流的,并忘记了MS SQL本地事务,直到陷入巨大的陷阱: Windows Server 2008 WEB Edition带有受限制的分布式事务协调器服务,而TransactionScope仅在单台计算机上工作。 如果IIS和SQL Server安装在不同的计算机上,则您的ASP.NET应用程序将在该系统上失败。请注意,大多数公共域提供商提供Windows Server WEB版,并且SQL Server位于单独的服务器上。这意味着您必须使用显式事务管理来使用本地事务...

4

我认为它们从根本上是相同的,即TransactionScope类将与ADO.NET底层连接进行交互,创建并提交或回滚事务。而TransactionScope类只是为了使使用ADO.NET持久性更加清晰明了。

编辑:casperOne的添加中,我想澄清我的说法:是TransactionScope将创建事务,然后连接将查看由TransactionScope创建的事务并使用它,因为这对它是可用的。


@Christ Marisic:恰恰相反。连接会查找当前线程的事务是否存在,这个事务将由TransactionScope创建。如果存在,则连接将与该事务注册。协调器随后会告诉连接提交或回滚。 - casperOne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接