.NET TransactionScopes и SQL 2005 облегченный диспетчер транзакций - несколько подключений один и тот же SPID? - PullRequest
0 голосов
/ 02 сентября 2010

Может ли кто-то пролить свет на то, что происходит за кулисами, с помощью диспетчера транзакций SQL Lightweight, когда несколько соединений открываются к одной и той же БД, используя прикладной блок доступа к данным Microsoft (DAAB) ?

С помощью приведенного ниже кода мы убедились, что MSDTC действительно не требуется при открытии «нескольких подключений» к одной и той же базе данных.

Это был первый протестированный мной сценарий: (где Txn1 и Txn2 используют EntLib 4.1 дляоткройте соединение с одной и той же БД и вызовите разные SPROCS)

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

Трассировка этого из профилировщика показала, что один и тот же SPID соединения использовался для Txn1 и Txn2.После вызова Txn1 () SPID Sql должен был быть возвращен обратно в пул, и 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();
}

Просмотр этого из Профилировщика показал, что 2 транзакции были ВСЕ ЕЩЕ, используя тот же SPID.Я ожидал, что TransactionScope перерастет в DTC, поскольку распределенная транзакция должна потребоваться для управления 2 одновременными подключениями.Что я пропустил?

Ответы [ 3 ]

1 голос
/ 08 сентября 2010

Sql 2005 или Sql 2008?
Если вы используете sql 2008, последовательность соединений open + close не преобразуется в распределенную транзакцию.Но все соединения должны использовать одну и ту же строку соединения.

(псевдокод)

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

1 голос
/ 07 сентября 2010

Цитирование из MSDN http://msdn.microsoft.com/en-us/library/8xx3tyca(VS.80).aspx

Пул соединений уменьшает количество раз, что новые соединения должны быть открытым. Пулер поддерживает владение физическим соединением. Управляет связями, сохраняя живой набор активных соединений для каждая данная конфигурация соединения. Всякий раз, когда пользователь звонит Open на соединение, смотритель смотрит есть доступное соединение в бассейн. Если пул соединения доступно, он возвращает его вызывающей стороне вместо открытия нового соединения. Когда приложение вызывает Close on соединение, пулер возвращает его к объединенному набору активных соединения вместо того, чтобы на самом деле закрывая это. Как только соединение вернулся в бассейн, готов использовать повторно при следующем открытом вызове.

То, что в транзакции использовалось соединение, не означает, что оно не может быть доступно для следующего вызова. Я обнаружил, что если строка соединения изменяется от малейшей вещи, например, от заглавных букв имени хоста, вы получите новое физическое соединение с БД.

0 голосов
/ 08 сентября 2010

ОК, мое недоразумение было с DAAB.DAAB Database открывает и закрывает соединения по мере необходимости (или получает / освобождает их из пула), то есть соединения не удерживаются в течение срока службы объекта DAAB Database.

Можно вручную управлять соединениями с базой данных в 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();
    }
}
...