2010-11-16 12 views
15

Estoy intentando escribir en un archivo de registro dentro de una transacción para que el registro sobreviva incluso si la transacción se revierte.Registro de TSQL dentro de la transacción

código --start

comienzan tran

insertar [algo] en dbo.logtable

[[código principal aquí]]

rollback

cometer

- fin código

Podría decir que simplemente haga el registro antes de que comience la transacción, pero eso no es tan fácil porque la transacción se inicia antes de que se ejecute este S-Proc (es decir, el código es parte de una transacción más grande)

Entonces, en resumen, ¿hay alguna manera de escribir una declaración especial dentro de una transacción que no es parte de la transacción. Espero que mi pregunta tenga sentido.

+0

Por favor, eche un vistazo a http://stackoverflow.com/questions/3725356/suppress-transaction-in-stored-procedure –

Respuesta

12

Utilice una variable de tabla (@temp) para contener la información de registro. Las variables de tabla sobreviven a una reversión de transacción.

Ver this article.

+0

Justo lo que iba a sugerir. Lo he usado exitosamente muchas veces. – HLGEM

+0

El problema con esto es si sucede algo más, como un tiempo de espera de conexión o un tiempo de espera de ejecución, le quedarán sin registros. – Talon

2

Hago esto de dos maneras, dependiendo de mis necesidades en ese momento. Ambos implican el uso de una variable, que conservan su valor después de una reversión.

1) Cree un valor de DECLARE @Log varchar(max) y use esto: @SET @ Log = ISNULL (@ Log + ';', '') + 'Su nueva información de registro aquí' . Keep appending to this as you go through the transaction. I'll insert this into the log after the commit or the rollback as necessary. I'll usually only insert the @Log value into the real log table when there is an error (in the CATCH` block) o Si estoy intentando depurar un problema

2) crear un DECLARE @LogTable table (RowID int identity(1,1) primary key, RowValue varchar(5000). Inserción en esto a medida que avance en su transacción. Me gusta usar la cláusula OUTPUT para insertar los ID reales (y otras columnas con mensajes, como 'ELIMINAR el elemento 1234') de las filas utilizadas en la transacción en esta tabla. Insertaré esta tabla en la tabla de registro real después de la confirmación o la reversión, según sea necesario.

+0

Ambos son buenos, excepto que no tengo acceso fácil a la parte de la transacción. Básicamente estoy intentando depurar un programa escrito en C#. – Arvid

+1

(terminemos esto :-) El código C# inicia una transacción, luego llama a un s-proc, y al final compromete o retrotrae la transacción. Solo tengo acceso fácil a s-proc y esperaba poder hacer algún código de depuración que sobreviviera a una reversión – Arvid

+0

que podría intentar con [xp_cmdshell (Transact-SQL)] (http://msdn.microsoft.com /es-es/library/ms175046.aspx) (pero puede estar desactivado como un riesgo de seguridad) para incluir esto en su procedimiento: 'EXEC xp_cmdshell echo 'su mensaje aquí' >> log.txt' para escribir en un archivo . también podría intentar usar un parámetro de salida @ErrorInfo varchar (max) 'donde devuelve la información de error al programa C# para que pueda iniciar sesión. –

1

Si la transacción principal se retrotrae, los datos de registro se retrotraerán también: el servidor SQL no admite transacciones anidadas apropiadas. Una posibilidad es utilizar un procedimiento almacenado CLR para hacer el registro. Esto puede abrir su propia conexión a la base de datos fuera de la transacción e ingresar y confirmar los datos del registro.

+0

El uso del procedimiento de registro CLR es una de las mejores soluciones. Si solo fuera posible de alguna manera obtener automáticamente los valores reales de los parámetros con los que se llamaba el sproc ... siempre podemos soñar. –

7

Consulte Logging messages during a transaction para una solución alternativa basada en sp_trace_generateevent que no requiere una variable variable de ámbito (que no siempre es posible) o cuando los límites de la transacción están fuera de control.

+0

Parece que esto funcionará. Gracias a todos por las respuestas rápidas. – Arvid

0

Si desea emular el comportamiento transacción anidada puede utilizar transacciones con nombre:

begin transaction a 

create table #a (i int) 

select * from #a 
save transaction b 

create table #b (i int) 
select * from #a 
select * from #b 

rollback transaction b 

select * from #a 
rollback transaction a 

En SQL Server si desea una ‘sub-transacción’ se debe utilizar save transaction xxxx que funciona como un puesto de control de Oracle.

+3

Esta respuesta no responde la pregunta en absoluto. El OP no pregunta por la subtransacción, sino todo lo contrario. Quiere que se excluya alguna operación del contexto de transacción y se comprometa de inmediato en la base de datos. – Tipx

+0

mi respuesta fue al comentario anterior, y creo que respondió de manera muy sucinta –

Cuestiones relacionadas