.NET TransactionScopes和SQL 2005轻量级事务管理器 - 多个连接相同的SPID?

时间:2010-09-02 13:43:48

标签: sql-server-2005 transactions transactionscope

当有人使用Microsoft Data Access Application Block (DAAB)向同一个数据库打开多个连接时,是否可以通过SQL Lightweight事务管理器了解幕后发生的事情?

使用以下代码,我们确认在打开同一数据库的“多个连接”时确实不需要MSDTC。

这是我测试的第一个场景:(其中Txn1和Txn2使用EntLib 4.1打开与同一个DB的连接并调用不同的SPROCS)

using (var ts = new TransactionScope(TransactionScopeOption.Required))
{
    DAL1.Txn1();
    DAL2.Txn2();
    ts.Complete();
}

从分析器跟踪此信息表明,相同的连接SPID用于Txn1和Txn2。在调用Txn1()之后,Sql SPID将被释放回池中,并且Txn2()能够重新使用它。

但是,重复此实验时,此时保持连接打开:

using (var ts = new TransactionScope(TransactionScopeOption.Required))
{
    Database db1 = DatabaseFactory.CreateDatabase("db1");
    DAL1.Txn1OnCon(db1);
    Database db2 = DatabaseFactory.CreateDatabase("db1");
    DAL2.Txn2OnCon(db2);
    ts.Complete();
}

从Profiler中查看此信息表明这2个事务仍处于使用相同SPID的STILL。我期望TransactionScope升级到DTC,因为应该需要分布式事务来控制2个并发连接。我错过了什么?

3 个答案:

答案 0 :(得分:1)

引自MSDN http://msdn.microsoft.com/en-us/library/8xx3tyca(VS.80).aspx

  

连接池减少了数量   新连接需要的时间   被打开了。这个消费者坚持认为   物理连接的所有权。   它通过保持来管理连接   活着一组活跃的连接   每个给定的连接配置。   每当用户在a上调用Open时   连接,pooler看起来是否   有一个可用的连接   游泳池。如果是汇集连接   可用,它将它返回给调用者   而不是打开一个新的连接。   当应用程序调用Close on时   连接,pooler返回它   汇集到积极的   连接而不是实际   关闭它。连接后   回到游泳池,它准备好了   在下次公开电话会议上重复使用。

仅仅因为在事务中使用了连接并不意味着它无法用于下一次调用。我发现如果连接字符串因最轻微的事情而变化,例如主机名的大小写,那么你将获得与数据库的新物理连接。

答案 1 :(得分:1)

Sql 2005或Sql 2008?
如果使用sql 2008,则一系列打开+关闭连接不会升级为分布式事务。但是所有连接必须使用完全相同的连接字符串。

(伪代码)

string connstring = "...."
using (TransactionScope ts=...)
{
  c1 = new connection(connstring );
  c1.open
  ...use c1
  c1.close

  c2 = new connection(connstring );
  c2.open
  ...use c2
  c2.close

  ts.complete()
}

与sql2005相同的代码升级为分布式事务 - >你需要MSDTC

答案 2 :(得分:0)

好的,我的错误是DAAB。 DAAB Database根据需要打开和关闭连接(或从池中获取/释放它们),即连接不会在DAAB Database对象的生命周期中保持。 / p>

可以按照以下手动控制DAAB中的数据库连接 - 通过保持实际连接打开,它们无法重复使用。这就要求MSDTC在2个物理连接打开后立即运行,正如我在原始问题中所预期的那样。

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
{
    using (DbConnection dbConn1 = DatabaseFactory.CreateDatabase("myDb").CreateConnection())
    using (DbConnection dbConn2 = DatabaseFactory.CreateDatabase("myDb").CreateConnection())
    {
        dbConn1.Open();
        DAL1.Txn1OnCon(dbConn1);
        dbConn2.Open();
        DAL2.Txn2OnCon(dbConn2);
        DAL1.Txn1OnCon(dbConn1);
        ts.Complete();
    }
}