IsolationLevel.ReadUncommitted блокирует чтение при другом подключении к SQL Server 2008

#c# #transactions #timeout

#c# #транзакции #тайм-аут

Вопрос:

Привет, у меня проблема с чтением из моей базы данных, когда вызывающий код имеет ожидающую транзакцию. Вот так:

 f1() {
DbTransaction t = Connection1.BeginTransaction(IsolationLevel.ReadUncommitted);
  ...
  f2();
  ...
  t.Commit();
}

f2() {
  Connection2.Execute("SELECT...");
}
 

Вызов f2() приводит к исключению тайм-аута.

Такое поведение было для меня неожиданным, потому что я думал, что IsolationLevel это позволит получить доступ на чтение к БД. Когда я удаляю транзакцию из f1() проблемы, проблема исчезает.

Я благодарен за любые комментарии по этому поводу и о том, как решить проблему. Я хотел бы сохранить транзакцию!

(Visual Studio 2010, C #, .NET 4.0, уровень совместимости с SQL Server 2008 80)

Комментарии:

1. Вы указали connection1 на чтение незафиксированных данных. Вы не сообщили об этом connection2.

Ответ №1:

Как говорит @Vijay, похоже, вам не нужно создавать здесь второе соединение, поэтому эта проблема легко решается с помощью того же соединения.

Однако для справки, чтобы объяснить, почему второе соединение блокируется:

Ваше первое соединение выполняется на уровне изоляции READ UNCOMMITTED , который все еще может создавать эксклюзивные блокировки. В какой-то момент между созданием Connection1 и вызовом f2() вы делаете что-то, чтобы создать эксклюзивную блокировку, которая блокирует инструкцию, выполняемую by f2() , которая выполняется на уровне изоляции по умолчанию READ COMMITTED .

Если вы хотите посмотреть, что происходит с блокировками, откройте два окна SSMS. В первом окне выполните следующие инструкции:

 set transaction isolation level read uncommitted
go

begin transaction 
-- alter some data
delete MyTable
waitfor delay '00:00:15'

rollback transaction
 

Во втором окне запустите sp_lock , чтобы увидеть включенные блокировки MyTable .

Ответ №2:

Я не уверен, почему вы открываете другой экземпляр подключения в f2(), поскольку похоже, что оба подключения относятся к одному и тому же серверу DB и DB. Вы можете просто передать экземпляр Connection1 из f1() в вызов метода f2() и повторно использовать.

 f1()
{
    ...

    f2(Connection1);

    ...
}

f2()
{
    Connection1.Execute(SELECT...);
}
 

Ответ №3:

Я предлагаю вам использовать TransactionScope в инструкции using для инициализации этих транзакций. Кроме этого, повторно используйте соединение, как рекомендовал Виджай.

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

Вы всегда можете открыть SQL studio и проверить список активных блокировок, пока второй выбор блокируется. Довольно простой способ точно выяснить, что блокирует.