#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 и проверить список активных блокировок, пока второй выбор блокируется. Довольно простой способ точно выяснить, что блокирует.