如果其中一个数据库是READ ONLY,是否会发生分布式事务升级?

时间:2010-01-14 17:32:13

标签: sql-server transactions transactionscope msdtc

我们正在从源数据库到目标数据库执行导入过程。我们需要经常以自动方式运行这些导入。

源位于与目标不同的服务器上。两者都是MS SQL 2008.我们使用Linq2SQL访问源,使用自定义数据层访问目标。我们不会修改源数据库(虽然我们目前不会将其恢复为只读)。但是,现在当我们在transactionScope中运行导入时,整个事务将被提升为DTC,因为我们在不同的服务器上访问两个DB。

如果我们要将源数据库设为只读,它还会这样做吗?

有关如何在此方案中避免DTC促销的任何其他建议?

Remus回答的后续问题(再次感谢):

后续行动#1: 我的导入例程的结构使得它从源中导入记录并在目标中创建新记录。像这样:

using(var scope = new TransactionScope())
{
   // read some from source db using Linq2Sql
   // transform source info
   // update destination

   // read some more from source db using Linq2Sql
   // transform source info
   // update destination

}

您是否想要使用RequiresNew在TransactionScope中包围Linq2Sql位?或者,我猜,我真的不关心源头上的交易,我可以用TransactionScope包围这个连接包含在任何交易中,对吧?

后续行动#2:

当你说“打开第二个连接,甚至连同一个数据库”时 - 我已经阅读了几个变种:​​

  1. “second connection”== Connection对象的第二个实例,即使它与connectionstring完全相同
  2. “第二次连接”==与单独的资源管理器和SQL2005的连接,在此之前与上面的1相同,但在SQL2008上,这意味着一个单独的实例(即同一实例上的两个DB不会被提升)

1 个答案:

答案 0 :(得分:2)

当您在事务范围内打开第二个ADO.Net连接时,两个连接都将被提升为DTC。即使是与同一个DB的新连接,也无所谓。数据库只读也与它无关,也不可能与它有任何关系。首先,连接不是特定于数据库的,因为它们可以在打开后更改数据库。其次,只读数据库可以执行大量写操作(例如,可以调用readonlydb.dbo.myProcedure,在程序中我可以更新writabledb.dbo.table)。

如果要避免使用DTC,则必须在两个访问层之间使用不同的事务范围(即使用RequireNew创建新范围)。

<强>更新

如果可以在范围之外进行读取,那将是完美的:

// read some from source db using Linq2Sql 
// read some more from source db using Linq2Sql 
using(var scope = new TransactionScope()) 
{ 
   // transform source info 
   // update destination 

   // transform source info 
   // update destination 
} 

我理解这是非常不可能的,因为第二组读取可能通常依赖于第一次转换/更新的结果。因此,在阅读时最好压缩范围:

using(var scope = new TransactionScope()) 
{ 
   using(var nada= new TransactionScope(TransactionScopeOption.Supress))
   {
       // read some from source db using Linq2Sql 
       // transform source info 
   }
   // update destination 

   using(var nada= new TransactionScope(TransactionScopeOption.Supress))
   {
       // read some more from source db using Linq2Sql
       // transform source info 
   } 
   // update destination 
} 

BTW我认为'使用linq读取一些数据'意味着你实际上枚举了查询,不要只创建查询表达式并稍后使用表达式。我不确切知道事务范围如何与查询表达式交互,但我的假设是范围适用于查询执行,而不是声明。