2012-07-13 15 views
5

Hace una reversión dentro de un INSERTAR DESPUÉS o una ACTUALIZACIÓN DESPUÉS del desencadenante revertir la transacción completa o solo la fila actual que es la razón para desencadenar, y es lo mismo con Commit?Hace una reversión dentro de un INSERTAR DESPUÉS o ACTUALIZAR DESPUÉS del desenganche de la transacción completa

Traté de verificarlo a través del código de mi proyecto actual que usa MSTDC para las transacciones, y parece como si la transacción completa hubiera sido cancelada.

Si una reversión en el desencadenador retrotrae la transacción completa, ¿hay alguna solución para restringirla solo a las filas actuales?

que encuentre un enlace de sybase en esto, pero no hay nada en el servidor SQL

+1

Doe SQL Server realmente permite un 'rollback' en un desencadenador? –

+0

Supongo que sí, b'coz escribí uno, y no arrojó ningún error al ejecutar el script y el desencadenador también funciona. – Vamsi

+1

Wow. Eso es aterrador –

Respuesta

7

Sí, va a deshacer toda la transacción.

Todo está en el docs (ver Comentarios). Tenga en cuenta el comentario que he enfatizado, ¡eso es muy importante, diría!

Si una transacción ROLLBACK se emite en un disparador:

Todas las modificaciones de datos realizadas a ese punto en la transacción actual se deshacen, incluyendo cualquier hecha por el gatillo.

El desencadenador continúa ejecutando las sentencias restantes después de la instrucción ROLLBACK. Si alguna de estas instrucciones modifica datos, las modificaciones no se revierten. La ejecución de estas sentencias restantes no desencadena disparadores anidados.

Las declaraciones en el lote después de la instrucción que activó el desencadenador no se ejecutan.

+1

Entonces, ¿alguna solución? – Vamsi

+4

¿Por qué necesitaría una solución alternativa? Un desencadenante es simplemente un código como cualquier otro código: usted controla exactamente dónde desea hacer retrocesos en todo momento. – Jimbo

+0

Creo que lo que está pidiendo es deshacer solo las filas involucradas con la instrucción de inserción/actualización que invocó el desencadenador. Para hacer eso, supongo que uno necesitaría establecer un punto de rescate en la persona que llama, llamar a la inserción/actualización, desde un lado del disparador generar un error basado en alguna lógica si es necesario, luego en la persona que llama capta el error y retrocede al punto de rescate . No lo intenté sin embargo. Un mejor diseño (sin excepción) podría ser verificar la condición en la persona que llama y ni siquiera intentar insertar/actualizar esas filas en primer lugar. – crokusek

0

Cualquier comando de reversión revertirá todo hasta que @@ trancount sea 0 a menos que especifique algunos puntos de guardado y no importa dónde coloque el comando rollback tran.

La mejor manera es mirar el código una vez más y confirmar el requisito de negocio y ver por qué necesita una retrotracción en el desencadenante?

1

Como ya le han informado, el comando ROLLBACK no se puede modificar/sintonizar para que solo retrotraiga las declaraciones emitidas por el desencadenador.

Si necesita una forma de "retrotraer" las acciones realizadas solo por el desencadenante, puede como una solución temporal, considere modificar su desencadenador de tal forma que antes de realizar las acciones, el desencadenador se asegure de que esas acciones no producir situaciones excepcionales que causarían la reversión de toda la transacción.

Por ejemplo, si su activador inserta filas, agregue una marca para asegurarse de que las nuevas filas no violen, p.restricciones únicas (o restricciones de clave externa), algo como esto:

IF NOT EXISTS (
    SELECT * 
    FROM TableA 
    WHERE … /* a condition to test if a row or rows you are about 
       to insert aren't going to violate any constraint */ 
) 
BEGIN 
    INSERT INTO TableA … 
END; 

O, si su gatillo elimina filas, compruebe si no trata de eliminar filas referenciadas por otras tablas (en cuyo caso normalmente se necesita saber de antemano qué tablas Might referencia las filas):

IF NOT EXISTS (
    SELECT * FROM TableB WHERE … 
) 
AND NOT EXISTS (
    SELECT * FROM TableC WHERE … 
) 
AND … 
BEGIN 
    DELETE FROM TableA WHERE … 
END 

Del mismo modo, lo que se necesita para hacer comprobaciones para instrucciones de actualización, si los hubiere.

Cuestiones relacionadas