2009-11-17 5 views
141

Tenemos aplicación cliente que se ejecuta en un poco de SQL Server 2005 SQL como la siguiente:Servidor SQL: ¿hay un error en las transacciones?

BEGIN TRAN; 
INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 
INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 
INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 
COMMIT TRAN; 

Se envía un comando de cadena larga.

Si una de las inserciones falla o si alguna parte del comando falla, ¿SQL Server retrotrae la transacción? Si no se revierte, ¿tengo que enviar un segundo comando para devolverlo?

Puedo dar detalles sobre la API y el idioma que estoy usando, pero creo que SQL Server debería responder de la misma manera para cualquier idioma.

+0

http://stackoverflow.com/questions/1150032/what-is-the-benefit-of-using-set- xact-abort-on-a-stored-procedure – zloctb

Respuesta

157

Usted puede poner set xact_abort on antes de su transacción para hacer rollos sql seguro atrás de forma automática en caso de error.

+1

¿Esto funcionará en MS SQL 2K y superior? Esta parece ser la solución más simple. – jonathanpeppers

+1

Aparece en los documentos para 2000, 2005 y 2008, por lo que supongo que sí. Lo estamos usando en 2008. – DyingCactus

+0

¿Existe una opción para revertir en un tiempo de espera de red o errores de red en general? ¿O esta opción maneja todo en uno? – jonathanpeppers

10

Si una de las inserciones falla o si alguna parte del comando falla, ¿el servidor SQL retrotrae la transacción?

No, no es así.

Si no se revierte, ¿tengo que enviar un segundo comando para devolverlo?

Claro, debería emitir ROLLBACK en lugar de COMMIT.

Si desea decidir si se debe confirmar o deshacer la transacción, debe quitar la sentencia COMMIT de la declaración, comprobar los resultados de los insertos y luego emitir ya sea COMMIT o ROLLBACK en función de los resultados de la verificación.

+0

Entonces, si recibo un error, diga "Conflicto de clave principal" ¿Necesito enviar una segunda llamada para deshacer?Supongo que eso tiene sentido. ¿Qué sucede si hay un error relacionado con la red, como la conexión se corta durante una instrucción SQL de ejecución muy larga? – jonathanpeppers

+2

Cuando una conexión expira, el protocolo de red subyacente (por ejemplo, 'Canalizaciones con nombre 'o' TCP') interrumpe la conexión. Cuando se rompe una conexión, 'SQL Server' detiene todos los comandos actualmente en ejecución y revierte la transacción. – Quassnoi

+1

Así que la solución de DyingCactus parece que soluciona mi problema, gracias por la ayuda. – jonathanpeppers

154

Tiene razón en que se retrotraerá toda la transacción. Debería ejecutar el comando para retrotraerlo.

se puede envolver esto en un bloque TRY CATCH de la siguiente manera

BEGIN TRY 
    BEGIN TRANSACTION 

     INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 
     INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 
     INSERT INTO myTable (myColumns ...) VALUES (myValues ...); 

    COMMIT TRAN -- Transaction Success! 
END TRY 
BEGIN CATCH 
    IF @@TRANCOUNT > 0 
     ROLLBACK TRAN --RollBack in case of Error 

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception 
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1) 
END CATCH 
+1

Me gusta más la solución de DyingCactus, esta es 1 línea de código para cambiar. Si es tuyo si por alguna razón mejor (o más confiable) házmelo saber. – jonathanpeppers

+9

El try catch le brinda la capacidad de capturar (y posiblemente corregir) el error y generar un mensaje de error personalizado si es necesario. –

+0

Como realmente no nos importa manejar el error específicamente dentro de SQL, creo que vamos con la solución de DyingCactus. – jonathanpeppers

15

Del artículo de MDSN, Controlling Transactions (Database Engine).

Si se produce un error de sentencia en tiempo de ejecución (como una infracción) en un lote, el comportamiento predeterminado en el motor de base de datos es retrotraer solo la sentencia que generó el error. Puede cambiar este comportamiento utilizando la instrucción SET XACT_ABORT. Después de ejecutar SET XACT_ABORT ON, cualquier error de instrucción en tiempo de ejecución provoca una reversión automática de la transacción actual. Los errores de compilación, como los errores de sintaxis, no se ven afectados por SET XACT_ABORT. Para obtener más información, vea SET XACT_ABORT (Transact-SQL).

En su caso, revertirá la transacción completa cuando falle cualquiera de las inserciones.

+1

¿Qué necesitamos para manejar los errores de sintaxis? o compilar errores? si alguno de ellos sucede que la transacción completa se debe retrotraer – MonsterMMORPG

7

Aquí el código con conseguir el mensaje de error trabajar con el Servidor MSSQL 2016:

BEGIN TRY 
    BEGIN TRANSACTION 
     -- Do your stuff that might fail here 
    COMMIT 
END TRY 
BEGIN CATCH 
    IF @@TRANCOUNT > 0 
     ROLLBACK TRAN 

     DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE() 
     DECLARE @ErrorSeverity INT = ERROR_SEVERITY() 
     DECLARE @ErrorState INT = ERROR_STATE() 

    -- Use RAISERROR inside the CATCH block to return error 
    -- information about the original error that caused 
    -- execution to jump to the CATCH block. 
    RAISERROR (@ErrorMessage, -- Message text. 
       @ErrorSeverity, -- Severity. 
       @ErrorState -- State. 
       ); 
END CATCH 
+1

tuve que usar 'DECLARE @Var TYPE; SET @Var = ERROR; 'para aumentar los errores en el servidor sql 2005. De lo contrario, el código anterior para generar errores también funciona para los DB más antiguos. Intentar asignar un valor predeterminado a una variable local es lo que causaba problemas. – jtlindsey

Cuestiones relacionadas