Csharp/C#教程:TransactionScope:避免分布式事务分享


TransactionScope:避免分布式事务

我有一个父对象(DAL的一部分),其中包含子对象的集合( List )。

当我将对象保存回DB时,我输入/更新父对象,然后循环遍历每个子对象。 为了可维护性,我将子项的所有代码放入一个单独的私有方法中。

我打算使用标准的ADO事务,但在我的旅行中,我偶然发现了TransactionScope对象,我相信这将使我能够在一个事务中将父方法中的所有数据库交互(以及子方法中的所有交互)包装起来。

到现在为止还挺好..?

接下来的问题是如何在TransactionScope中创建和使用连接。 我听说使用多个连接,即使它们属于同一个DB,也可能迫使TransactionScope认为它是一个分布式事务(涉及一些昂贵的DTC工作)。

是这样吗? 或者是,正如我似乎在其他地方读到的那样,使用相同的连接字符串(它将自己用于连接池)的情况会好吗?

更实际的是,我……

  1. 在父和子中创建单独的连接(尽管具有相同的连接字符串)
  2. 在父项中创建一个连接作为参数传递它(对我来说似乎很笨拙)
  3. 做点什么……?

更新:

虽然看起来我可以使用我常用的.NET3.5 +和SQL Server 2008+,但这个项目的另一部分将使用Oracle(10g),所以我不妨练习一种可以跨项目使用的技术。

所以我只是简单地将连接传递给子方法。


选项1代码示例:

 using (TransactionScope ts = new TransactionScope()) { using (SqlConnection conn = new SqlConnection(connString)) { using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.Connection.Open(); cmd.CommandType = CommandType.StoredProcedure; try { //create & add parameters to command //save parent object to DB cmd.ExecuteNonQuery(); if ((int)cmd.Parameters["@Result"].Value != 0) { //not ok //rollback transaction ts.Dispose(); return false; } else //enquiry saved OK { if (update) { enquiryID = (int)cmd.Parameters["@EnquiryID"].Value; } //Save Vehicles (child objects) if (SaveVehiclesToEPE()) { ts.Complete(); return true; } else { ts.Dispose(); return false; } } } catch (Exception ex) { //log error ts.Dispose(); throw; } } } } 

当您使用TransactionScope跨多个连接进行交易时,许多数据库ADO提供程序(例如Oracle ODP.NET)确实会开始分布式事务 – 即使它们共享相同的连接字符串。

某些提供程序(如.NET 3.5+中的SQL2008)识别何时在引用相同连接字符串的事务范围中创建新连接,并且不会导致DTC工作。 但是连接字符串中的任何差异(例如调整参数)都可能阻止这种情况发生 – 并且行为将恢复为使用分布式事务。

遗憾的是,确保您的事务在不创建分布式事务的情况下协同工作的唯一可靠方法是将连接对象(或IDbTransaction )传递给需要在同一事务上“继续”的方法。

有时它有助于提升与您正在进行工作的类的成员的连接,但这可能会创建尴尬的情况 – 并且使控制连接对象的生命周期和处置变得复杂(因为它通常会排除使用using语句)。

根据经验,我已经确定(对于SQL Server提供程序) 如果进程可以利用连接池来共享父进程和子进程之间的连接(和事务),则DTC不一定会涉及到。

这是一个很大的“if”,但是,根据您的示例,父进程创建的连接不能由子进程共享(在调用子进程之前不要关闭/释放连接)。 这将导致跨越两个实际连接的事务,这将导致事务被提升为分布式事务。

似乎很容易重构代码以避免这种情况:在调用子进程之前,只需关闭父进程创建的连接。

在您的示例中,TransactionScope仍然在方法的上下文中,您可以简单地创建一个带有多个命令的SqlTransaction。 如果要将事务移出方法(例如,该方法的调用方,或者访问多个数据库),请使用TransactionScope。

更新:没关系,我只是发现了孩子的电话。 在这种情况下,您可以将连接对象传递给子类。 此外,您不需要手动处理TransactionScope – 使用块就像try-finally块一样,即使在exception情况下也会执行dispose。

更新2:更好的是,将IDbTransaction传递给子类。 可以从中检索连接。

上述就是C#学习教程:TransactionScope:避免分布式事务分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1027258.html

(0)
上一篇 2022年1月9日
下一篇 2022年1月9日

精彩推荐