LINQ to SQL中的TransactionScope与事务


76

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
    {
    }
}

Answers:


37

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

从文档(重点是我的):

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


10
如果需要提交具有周期性属性的内容(常见),请在LINQ to SQL中遇到一个错误,该错误要求您删除每个2向引用的一部分,提交,修复2向引用,然后再次提交。您需要将所有这些包装在您自己的事务中,以实现此目的。这是常见的需求,因此“不要担心”不是最佳答案。
克里斯·莫斯奇尼

76

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

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

调用BeginTransactionDbConnection对象时,如果要在同一事务中执行其他操作,但要使用另一种方法,则必须传递该事务对象。

使用TransactionScope,只要作用域存在,它就会处理所有Transaction在线程上向当前注册的内容,从而使您的代码更干净,更可维护。

最重要的是,您还有一个额外的好处,就是能够使用其他可以参与事务的资源,而不仅仅是与数据库的连接。

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

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

或者,如果您知道您将一致地(在同一线程上)使用一种资源,则可能需要创建一个引用计数您的连接/事务的类。

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

这使您可以将事务管理与逻辑代码分开,并且仍然可以非常有效地保留单个资源(而不是升级为分布式事务)。


如果我在事务中使用单一连接,那不是同一回事吗?我的意思是你避免分布式事务..
GorillaApe

@Parhs取决于您是否通过单个数据库连接在事务中征用了其他事务资源。
casperOne 2012年

我的提供程序不允许嵌套事务(数据库),所以还有问题吗?
GorillaApe 2012年

2
@Parhs它不是关于数据库供应商,但你可以有一个事务文件系统,事务Web服务等,如果这些东西都包含在一个单一的数据库连接的事务,DTC的步骤。
casperOne

21

一个很大的不同(经验教训很艰辛)– TransactionScope使用MS DTC进行事务管理。

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


我也很难学到这一点!但是很高兴与msdtc解决了一场噩梦
DevDave 2012年

Mayank(或其他任何人)。我在使用Transaction和UnitTesting时遇到了其他问题,请问您能用这个stackoverflow.com/questions/9636533/…帮我吗?
DevDave 2012年

6
并非总是如此。 TransactionScope将根据需要从内核事务升级为DTC事务。但是,这一切对您都是隐藏的。重要的一点是它并不总是这样做,而是根据需要执行
casperOne 2014年

如果您使用相同的数据上下文,则不会。
Dasith Wijes '16

7

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


4

我相信它们在本质上是相同的,即TransactionScope类将与ADO.NET基础连接交互以创建并提交或回滚事务。刚刚创建TransactionScope类是为了使用ADO.NET持久性清洁器。

编辑:澄清我对casperOne添加的声明,由TransactionScope创建事务,然后连接将看到由TransactionScope创建的事务并使用它,因为它可用。


@Christ Marisic:就是相反。该连接查找当前线程的事务的存在,该事务将由TransactionScope创建。如果有一个,则它参与事务。然后,协调器将告诉连接进行提交或回滚。
casperOne
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.