Desde una aplicación .NET 3.5 / C #, me gustaría capturar, SqlException
pero solo si es causado por interbloqueos en una instancia de SQL Server 2008.
El mensaje de error típico es Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Sin embargo, no parece ser un código de error documentado para esta excepción.
Filtrar la excepción contra la presencia de la palabra clave interbloqueo en su mensaje parece una forma muy fea de lograr este comportamiento. ¿Alguien sabe la forma correcta de hacer esto?
.net
sql-server-2008
deadlock
try-catch
sqlexception
Joannes Vermorel
fuente
fuente
select * from master.dbo.sysmessages where error=1205
Respuestas:
El código de error específico de Microsft SQL Server para un interbloqueo es 1205, por lo que deberá manejar la SqlException y verificarlo. Entonces, por ejemplo, si para todos los demás tipos de SqlException desea que la burbuja muestre la excepción:
O, usando el filtrado de excepciones disponible en C # 6
Una cosa útil para encontrar el código de error SQL real para un mensaje dado es buscar en sys.messages en SQL Server.
p.ej
Una forma alternativa de manejar los interbloqueos (de SQL Server 2005 y superior) es hacerlo dentro de un procedimiento almacenado utilizando el soporte TRY ... CATCH:
Hay un ejemplo completo aquí en MSDN de cómo implementar la lógica de reintento de interbloqueo puramente dentro de SQL.
fuente
SqlException
puede estar envuelto en otro. Por lo tanto, es posible que necesitemos capturar cualquier tipo de excepción y verificarlos, luego, si no son directamente una excepción de interbloqueo, verifique recursivamente suInnerException
.Debido a que supongo que posiblemente desee detectar interbloqueos, para poder volver a intentar la operación fallida, me gustaría advertirle sobre un pequeño problema. 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 la hubiera), mientras la conexión se mantiene abierta en .NET. Reintentar esa operación (en esa misma conexión), significa que se ejecutará en un contexto sin transacciones y esto podría conducir a la corrupción de datos.
Es importante estar consciente de esto. Es mejor considerar que la conexión completa está condenada al fracaso en caso de una falla causada por SQL. Reintentar la operación solo se puede hacer en el nivel donde 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 y comenzar una nueva transacción.
fuente
A continuación se muestra una forma de C # 6 de detectar interbloqueos.
Asegúrese de que este try..catch rodee toda su transacción. De acuerdo con @Steven (vea su respuesta para más detalles), cuando el comando sql falla debido al punto muerto, 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 de datos.
fuente