2010-08-03 22 views
7

Nuestra aplicación (que utiliza NHibernate y ASP.NET MVC), cuando se somete a pruebas de resistencia arroja una gran cantidad de errores de transacción de NHibernate. Los tipos principales son:Manejar errores de transacción de NHibernate

  1. Transacción no está conectado, o se desconectó
  2. fila se ha actualizado o eliminado por otra transacción (o mapeo no salva-valor era incorrecta)
  3. transacción (ID de proceso 177) quedó en interbloqueo en bloquear recursos con otro proceso y se ha elegido como la víctima de interbloqueo. Vuelva a ejecutar la transacción.

¿Alguien me puede ayudar a identificar el motivo de la excepción 1? Sé que tengo que manejar las otras excepciones en mi código. ¿Puede alguien señalarme los recursos que pueden ayudarme a manejar estos errores de manera eficiente?

P. ¿Cómo gestionamos las Sesiones y las Transacciones?

A. Estamos utilizando Autofac. Para cada solicitud de servidor, creamos un nuevo contenedor de solicitud que tiene la sesión en el ámbito de duración del contenedor. Al activar la sesión, comenzamos la transacción. Cuando la solicitud se completa, confirmamos la transacción. En algunos casos, la transacción puede ser enorme. Para simplificar, cada solicitud del servidor está contenida en una transacción.

+0

¿Cómo gestionas las sesiones y las transacciones? –

+0

¿alguna vez encontró una solución a esto? –

Respuesta

1

Tener un vistazo a este tema: http://n2cms.codeplex.com/Thread/View.aspx?ThreadId=85016

Básicamente lo que dice como una posible causa de esta excepción:

2010-02-17 21: 01: 41,204 1 WARN NHibernate.Util.ADOExceptio nReporter - System.Data.SqlClient.SqlException: El registro de transacciones para la base de datos 'databasename' está lleno. Para averiguar por qué el espacio en el registro no puede ser reutilizado, ver columna log_reuse_wait_desc en sys.databases

medida que el tamaño del registro de transacciones es proporcional a la cantidad de trabajo realizado durante la transacción, tal vez usted debe busque en poner sus límites transaccionales en el manejo de los manejadores de comandos de los comandos en la parte de escritura de las transacciones. Luego, con una sesión n. ° X, cargue el estado que desea mutar, muévalo y confírmelo, todo como una unidad de trabajo en #X.

Con respecto al lado de lectura de las cosas, es posible que tenga otra ISession # Y que lea datos; esta ISession se puede usar para leer por lotes, p. RepeatableRead o algo similar con la función Futures y podría simplemente estar leyendo desde un caché (aunque es una muleta). Hacerlo de esta manera puede ayudarlo a recuperarse de "errores" que no lo son; livelocks, deadlocks y transacciones de víctimas.

El problema con el uso de una transacción por solicitud es que su ISession adquiere una gran cantidad de datos contables mientras trabaja, todo lo cual es parte de la transacción.Por lo tanto, la base de datos marca los datos (rols, cols, tables, etc.) como participantes en la transacción, haciendo que el gráfico de espera abarque "entidades" (en el sentido de la base de datos, no el DDD-sense), que en realidad no son parte del límite transaccional del comando que tomó su aplicación.

Para el registro (otras personas buscando en Google esto), Fabio tenía a post que trata de hacer frente a las excepciones de la capa de datos. Citando parte de su código;

public class MsSqlExceptionConverterExample : ISQLExceptionConverter 
{ 
    public Exception Convert(AdoExceptionContextInfo exInfo) 
    { 
     var sqle = ADOExceptionHelper.ExtractDbException(exInfo.SqlException) as SqlException; 
     if(sqle != null) 
     { 
      switch (sqle.Number) 
      { 
       case 547: 
        return new ConstraintViolationException(exInfo.Message, 
         sqle.InnerException, exInfo.Sql, null); 
       case 208: 
        return new SQLGrammarException(exInfo.Message, 
         sqle.InnerException, exInfo.Sql); 
       case 3960: 
        return new StaleObjectStateException(exInfo.EntityName, exInfo.EntityId); 
      } 
     } 
     return SQLStateConverter.HandledNonSpecificException(exInfo.SqlException, 
      exInfo.Message, exInfo.Sql); 
    } 
} 
  • 547 es el número de excepción de conflictos de restricciones.
  • 208 es el número de excepción para un nombre de objeto no válido en el SQL.
  • 3960 es el número de excepción para la transacción de aislamiento de instantánea cancelada debido a un conflicto de actualización.

Así que si se encuentra con problemas de simultaneidad como los que describe; recuerde que invalidarán su ISession y que usted tendrá que manejarlos como los anteriores.

Parte de lo que usted podría estar buscando es CQRS, donde tiene lados de lectura y escritura separados. Esto podría ayudar: http://abdullin.com/cqrs/, http://cqrsinfo.com.

Así que para resumir; sus problemas pueden estar relacionados con la forma en que maneja sus transacciones. Además, intente ejecutar select log_wait_reuse_desc from sys.databases where name='MyDBName' y vea lo que le ofrece.

1

Esta discusión tiene una explicación: http://groups.google.com/group/nhusers/browse_thread/thread/7f5fb68a00829d13

En resumen, la base de datos, probablemente, deshace la transacción por sí mismo debido a algún error, por lo que cuando se intenta deshacer la transacción después que ya se rueda hacia atrás y en un estado zombie. Esto tiende a ocultar el motivo real de la reversión ya que todo lo que ve es una TransactionException en lugar de la excepción que realmente desencadenó la reversión en primer lugar.

No creo que haya mucho que pueda hacer al respecto más allá de iniciar sesión y tratar de descubrir qué está causando el error subyacente.

0

Sé que esta publicación fue hace un tiempo y supongo que la corrigió, pero parece que tiene problemas de distribución de subprocesos con NHibernate ISession que no es insegura. Básicamente, 1 hilo está iniciando una transacción y otro está intentando cerrarlo, causando todo tipo de caos.

Cuestiones relacionadas