Contamos con tu ayuda para extender nuestros tutoriales sobre las ciencias de la computación.
Solución:
El código de error específico de Microsft SQL Server para un interbloqueo es 1205, por lo que deberá controlar la SqlException y comprobarlo. Entonces, por ejemplo, si para todos los demás tipos de SqlException desea que la burbuja aumente la excepción:
catch (SqlException ex)
if (ex.Number == 1205)
// Deadlock
else
throw;
O bien, utilizando el filtrado de excepciones disponible en C# 6
catch (SqlException ex) when (ex.Number == 1205)
// Deadlock
Una cosa útil para encontrar el código de error de SQL real para un mensaje determinado es buscar en sys.messages en SQL Server.
p.ej
SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033
Una forma alternativa de manejar interbloqueos (de SQL Server 2005 y superior) es hacerlo dentro de un procedimiento almacenado usando el soporte 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
Hay un ejemplo completo aquí en MSDN de cómo implementar la lógica de reintento de punto muerto puramente dentro de SQL.
Debido a que supongo que posiblemente desee detectar interbloqueos, para poder volver a intentar la operación fallida, me gustaría advertirle un poco. Espero que me disculpe por estar un poco fuera de tema aquí.
Un interbloqueo detectado por la base de datos revertirá efectivamente la transacción en la que estaba ejecutando (si corresponde), mientras que la conexión se mantiene abierta en .NET. Volver a intentar esa operación (en esa misma conexión), significa que se ejecutará en un contexto sin transacciones y esto podría provocar daños en los datos.
Es importante ser consciente de esto. Es mejor considerar la conexión completa condenada en caso de una falla causada por SQL. Solo se puede volver a intentar la operación en el nivel en el que se define la transacción (recreando esa transacción y su conexión).
Entonces, cuando vuelva a intentar una operación fallida, asegúrese de abrir una conexión completamente nueva e iniciar una nueva transacción.
Aquí hay una forma C# 6 de detectar interbloqueos.
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
Asegúrese de que este try..catch rodee toda su transacción. Según @Steven (consulte su respuesta para obtener más detalles), cuando el comando sql falla debido al interbloqueo, hace que la transacción se revierta y, si no vuelve a crear la transacción, su reintento se ejecutará fuera del contexto de la transacción y puede resultar en inconsistencias en los datos.
Reseñas y valoraciones
Al final de todo puedes encontrar las reseñas de otros usuarios, tú también puedes insertar el tuyo si te apetece.