try transaction stored example catch begin all .net sql-server sql-server-2005 transactions

.net - transaction - try catch sql server 2005



SqlTransaction ha completado (9)

Bueno, primero IMO, no deberías esperar que tu aplicación lidie con errores "difíciles" como estos. Su aplicación debe comprender cuáles son estas reglas comerciales y tenerlas en cuenta. NO obligue a su base de datos a ser la regla de negocios o la regla de la restricción cop. Solo debe ser un policía de reglas de datos y, en ese sentido, debe ser amable al decirle a la interfaz con RETURNs y otros métodos. Las cosas de los esquemas no deberían ir tan lejos.

Siguiendo con tu pregunta, sospecho que, sin ver ninguno de tus códigos, estás intentando cometer un error cuando ha ocurrido un error y todavía no lo sabes. Este es el razonamiento detrás de mi primera declaración ... tratando de atrapar el error que da la base de datos, sin que su aplicación comprenda y participe en estas reglas, se está produciendo un dolor de cabeza.

Prueba esto. Inserte filas que no fallarán con una restricción de la base de datos u otros errores y procese las inserciones con una confirmación. Mira qué pasa. Luego, introduzca algunos registros que fallarán, procese un compromiso y vea si obtiene su error encantador. Tercero, ejecute los errores nuevamente, haga un retroceso forzado y vea si tiene éxito.

Solo algunas ideas. Nuevamente, como resumen, creo que tiene que ver con no atrapar ciertos errores de la base de datos de una manera elegante para las cosas que son errores "duros" y esperar que el extremo frontal se ocupe de ellos. Una vez más, mi opinión experta, NOPE, no lo hagas. Es un desastre. Su aplicación debe superponerse en el conocimiento sobre las reglas en la parte posterior. Esas cosas están en su lugar solo para asegurarse de que esto no ocurra durante las pruebas, y el error ocasional que surge de esta manera, para luego colocarlo en la parte frontal para manejar la búsqueda olvidada en un conjunto de tablas de claves externas.

Espero eso ayude.

Tengo una aplicación que potencialmente hace miles de inserciones en una base de datos de SQL Server 2005. Si una inserción falla por algún motivo (restricción de clave externa, longitud del campo, etc.), la aplicación está diseñada para registrar el error de inserción y continuar.

Cada inserción es independiente de las otras, por lo que las transacciones no son necesarias para la integridad de la base de datos. Sin embargo, deseamos utilizarlos para la ganancia de rendimiento. Cuando uso las transacciones, obtendremos el siguiente error en aproximadamente 1 de cada 100 confirmaciones.

This SqlTransaction has completed; it is no longer usable. at System.Data.SqlClient.SqlTransaction.ZombieCheck() at System.Data.SqlClient.SqlTransaction.Commit()

Para intentar rastrear la causa, puse declaraciones de seguimiento en cada operación de transacción para poder asegurar que la transacción no se cerró antes de llamar a confirmación. He confirmado que mi aplicación no cerrará la transacción. Luego volví a ejecutar la aplicación utilizando exactamente los mismos datos de entrada y se realizó correctamente.

Si desactivo el cierre de sesión vuelve a fallar. Vuelve a encenderlo y lo consigue. Este cambio de activación / desactivación se realiza a través de app.config sin la necesidad de volver a compilar.

Obviamente, el acto de registro cambia el tiempo y hace que funcione. Esto indicaría un problema de subprocesos. Sin embargo, mi aplicación no es multihilo.

He visto una entrada de MS KB que indica que un error con el marco .Net 2.0 podría causar problemas similares ( http://support.microsoft.com/kb/912732 ). Sin embargo, la solución que proporcionaron no resuelve este problema.


Difícil ayudar sin ver el código. Supongo que, según su descripción, está utilizando una transacción para confirmar después de cada N inserciones, lo que mejorará el rendimiento en comparación con la confirmación de cada inserción, siempre que N no sea demasiado grande.

Pero el inconveniente es: si falla una inserción, cualquier otra inserción dentro del lote actual de N se retrotraerá cuando restituya la transacción.

En general, debe deshacerse de una transacción antes de cerrar la conexión (lo que revertirá la transacción si no se ha confirmado). El patrón habitual se parece a lo siguiente:

using(SqlConnection connection = ...) { connection.Open(); using(SqlTransaction transaction = connection.BeginTransaction()) { ... do stuff ... transaction.Commit(); // commit if all is successful } // transaction.Dispose will be called here and will rollback if not committed } // connection.Dispose called here

Por favor, publique el código si necesita más ayuda.


Esta excepción se produce porque la transacción real de la base de datos ya se ha retrotraído, por lo que un objeto .NET que lo representa en el lado del cliente ya es un "zombi".

Una explicación más detallada está here . Esta publicación explica cómo escribir un código de reversión de transacción correcto para tales escenarios.


Gracias por todos los comentarios. He estado trabajando con alguien de MSFT en los foros de MSDN para averiguar qué está pasando. Resulta que el problema se debe a que una de las inserciones falla debido a un problema de conversión de fecha y hora.

El principal problema es el hecho de que este error aparece si se trata de un error de conversión de fecha. Sin embargo, si es otro error, como que un campo sea demasiado largo, no causa este problema. En ambos casos, esperaría que la transacción aún existiera, por lo que puedo hacer clic en Revertir.

Tengo un programa de ejemplo completo para replicar este problema. Si alguien desea verlo o intercambiarlo con MSFT, puede encontrar el hilo en los grupos de noticias de MSFT en microsoft.public.dotnet.framework.adonet debajo del hilo de error SqlTransaction.ZombieCheck.


Mi problema era similar, y resultó que me lo estaba haciendo a mí mismo. Estaba ejecutando un montón de scripts en un proyecto VS2008 para crear procedimientos almacenados. En uno de los procs, utilicé una transacción. El script estaba ejecutando la creación del proceso dentro de una transacción, en lugar de incluir el código de la transacción como parte del procedimiento. Entonces, cuando llegó al final sin error, confirmó la transacción para el script. El código .Net también estaba usando y luego confirmando una transacción, y el efecto zombie se produjo cuando intentaba cerrar la transacción que ya se había cerrado dentro del script SQL. Eliminé la transacción del script SQL, confiando en la transacción abierta y verifiqué el código .Net, y esto resolvió el problema.


Según este post: http://blogs.msdn.com/b/dataaccesstechnologies/archive/2010/08/24/zombie-check-on-transaction-error-this-sqltransaction-has-completed-it-is-no -longer-usable.aspx

Una solución temporal podría ser intentar capturar la operación de retrotracción o confirmación. Entonces este código será suficiente para detener el error que se va a lanzar:

public static void TryRollback(this System.Data.IDbTransaction t) { try { t.Rollback(); } catch (Exception ex) { // log error in my case } } public static void TryCommit(this System.Data.IDbTransaction t) { try { t.Commit(); } catch (Exception ex) { // log error in my case } }

Consulte este ejemplo en el sitio web de msdn: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.aspx


También me enfrenté al mismo problema.

This SqlTransaction has completed; it is no longer usable

Después de investigar un poco, descubrí que el tamaño del archivo de registro de la base de datos es de 40 GB.
Es un gran volumen de datos lo que hace que mi transacción de SQL no esté comprometida.

Por lo tanto, mi solución es shrink el tamaño del archivo de registro al ver este enlace de referencia .

CREATE PROCEDURE sp_ShrinkLog_ByDataBaseName( @DataBaseName VARCHAR(200) ) AS BEGIN DECLARE @DBName VARCHAR(200) DECLARE @LogFileName VARCHAR(200) SET @DBName = @DataBaseName SELECT @LogFileName = [Logical File Name] FROM ( SELECT DB_NAME(database_id) AS "Database Name", type_desc AS "File Type", name AS "Logical File Name", physical_name AS "Physical File", state_desc AS "State" FROM SYS.MASTER_FILES WHERE database_id = DB_ID(@DBName) and type_desc = ''LOG'' ) AS SystemInfo SELECT LogFileName = @LogFileName EXECUTE( ''USE '' + @DBName + ''; -- Truncate the log by changing the database recovery model to SIMPLE. ALTER DATABASE '' + @DBName + '' SET RECOVERY SIMPLE; -- Shrink the truncated log file to 1 MB. DBCC SHRINKFILE ('' + @LogFileName + '', 1); -- Reset the database recovery model. ALTER DATABASE '' + @DBName + '' SET RECOVERY FULL; '') END

Luego EXEC sp_ShrinkLog_ByDataBaseName ''Yor_DB_NAME'' .

Si esto no funciona para usted, aquí hay http://support.microsoft.com/kb/912732 que creo que funcionará.


Tenga en cuenta que su aplicación no es el único participante en la transacción, también está involucrado el servidor SQL.

El error que usted cita:

Esta Transacción Sql ha completado; ya no es utilizable en System.Data.SqlClient.SqlTransaction.ZombieCheck () en System.Data.SqlClient.SqlTransaction.Commit ()

no indica que la transacción se ha comprometido, solo que está completa.

Mi primera sugerencia es que su servidor canceló la transacción porque tomó demasiado tiempo (tiempo de espera) o se hizo demasiado grande (demasiados cambios o demasiados bloqueos).

Mi segunda sugerencia es verificar que esté limpiando las conexiones y las transacciones de manera adecuada. Es posible que tengas problemas porque ocasionalmente estás agotando un conjunto de recursos antes de que las cosas se reciclen automáticamente.

Por ejemplo, DbConnection implementa IDisposable , por lo que debe asegurarse de que realiza la limpieza de manera adecuada, con una declaración de using , si puede, o llamando a Dispose() directamente si no puede. ''DbCommand'' es similar, ya que también implementa IDisposable .


Usted ha demostrado que sus datos están bien más allá de toda duda razonable.
FWIW, preferiría mover la inserción a un SPROC y no utilizar la transacción en absoluto.
Si necesita que la IU responda, use un trabajador de fondo para hacer el gruñido de la base de datos.
Para mí, una transacción es para actividades interrelacionadas, no un dispositivo que ahorra tiempo. El costo de inserción debe pagarse en algún lugar a lo largo de la línea.

Recientemente utilicé el perfilador ANTS en una aplicación de base de datos y me sorprendió ver las excepciones intermitentes de SQlClient que se muestran en el código de rendimiento sólido. Los errores son profundos en el marco al abrir una conexión. Nunca llegan a la superficie y no son detectables por el código del cliente. Entonces ... ¿El punto?
No todo es sólido, quita el trabajo pesado de la interfaz de usuario y acepta el costo. HTH Bob