Из приложения .NET 3.5 / C # я бы хотел поймать, SqlException
но только если это вызвано тупиками в экземпляре SQL Server 2008.
Типичное сообщение об ошибке: Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Тем не менее, это не похоже на документированный код ошибки для этого исключения.
Отфильтровать исключение против присутствия ключевого слова deadlock в их сообщении кажется очень уродливым способом добиться такого поведения. Кто-нибудь знает, как это сделать?
.net
sql-server-2008
deadlock
try-catch
sqlexception
Джоаннес Верморель
источник
источник
select * from master.dbo.sysmessages where error=1205
Ответы:
Код ошибки Microsoft SQL Server для взаимоблокировки - 1205, поэтому вам нужно обработать SqlException и проверить это. Итак, например, если для всех других типов SqlException вы хотите, чтобы исключение поднялось вверх:
Или, используя фильтрацию исключений, доступную в C # 6
Чтобы найти фактический код ошибки SQL для данного сообщения, удобно заглянуть в sys.messages в SQL Server.
например
SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033
Альтернативный способ обработки взаимоблокировок (начиная с SQL Server 2005 и выше) - это делать это внутри хранимой процедуры с помощью поддержки TRY ... CATCH:
BEGIN TRY -- some sql statements END TRY BEGIN CATCH IF (ERROR_NUMBER() = 1205) -- is a deadlock ELSE -- is not a deadlock END CATCH
Там есть полный пример здесь в MSDN , как реализовать логику повторных попыток тупиковой чисто в SQL.
источник
SqlException
может быть заключен в другой. Таким образом, нам может потребоваться перехватить любые исключения и проверить их, а затем, если они не являются непосредственно исключением тупиковой ситуации, рекурсивно проверить ихInnerException
.Поскольку я полагаю, что вы, возможно, хотите обнаружить тупиковые ситуации, чтобы иметь возможность повторить неудачную операцию, я хотел бы предупредить вас о небольшом затруднении. Я надеюсь, вы извините меня за то, что я здесь немного не по теме.
Тупиковая ситуация, обнаруженная базой данных, эффективно откатит транзакцию, в которой вы работали (если таковая имеется), в то время как соединение остается открытым в .NET. Повторная попытка этой операции (в том же соединении) означает, что она будет выполнена в контексте без транзакций, и это может привести к повреждению данных.
Об этом важно знать. Лучше всего считать полное соединение обреченным в случае сбоя, вызванного SQL. Повторная попытка операции может быть выполнена только на уровне, на котором определена транзакция (путем воссоздания этой транзакции и ее подключения).
Поэтому, когда вы пытаетесь выполнить неудачную операцию, убедитесь, что вы открыли совершенно новое соединение и начали новую транзакцию.
источник
Вот способ обнаружения тупиковых ситуаций в C # 6.
try { //todo: Execute SQL. //IMPORTANT, if you used Connection.BeginTransaction(), this try..catch must surround that code. You must rollback the original transaction, then recreate it and re-run all the code. } catch (SqlException ex) when (ex.Number == 1205) { //todo: Retry SQL }
Убедитесь, что этот try..catch охватывает всю вашу транзакцию. Согласно @Steven (подробности см. В его ответе), когда команда sql выходит из строя из-за тупиковой ситуации, это вызывает откат транзакции, и, если вы не воссоздаете транзакцию, ваша повторная попытка будет выполняться вне контекста транзакции и может привести к несогласованности данных.
источник