Excepción de transacción no activa - Estado de transacción EJB

Tengo un problema con los componentes de EJB que son responsables de iniciar una transacción. Estoy usando Jboss 5.01.

Básicamente, me gustaría ejecutar un código determinado después de que se haya comprometido una transacción específica. el código específico también implica llamar a un componente EJB que realiza sus propias transacciones.

Para asegurarme de que mi código se ejecute después de que se confirme una transacción anterior, he registrado un componente de sincronización en un componente de transacción:

Transaction tx = transactionManager.getTransaction();
tx.registerSynchronization(new CallbackSynchronization());

La Synchronizaton la implementación básicamente hace lo siguiente:

class CallbackSynchronization implements Synchnronization {

    private AccountService service;  // This is a Stateless session bean

    public CallbackSynchronization(AccountService service) {
        this.service   = service;
    }

    public afterCompletion(int status) {
        if(Status.STATUS_COMMITTED == status) {
            service.deleteAccounts();
        }
    }
}

El problema es que cuando llamo al service.deleteAccounts() Recibo una excepción que finalmente me dice que la transacción no está activa.

Y esto es lo que me confunde. un EJB con métodos marcados con @TransactionAttribute(TransactionAttributeType.REQUIRED) creará una nueva transacción si una no está activa (el REQUERIDO es el predeterminado en JBOSS).

Entonces, ¿por qué aparece "Transacción no activa"?

Muchas gracias,

Yaniv

preguntado el 30 de enero de 12 a las 19:01

1 Respuestas

El problema es que la transacción original que inició todavía está asociada con el hilo (aunque esté en un estado COMPROMETIDO). Una de las diferencias significativas entre usar el transacción y TransactionManager es que el ultimo cometer() y Retroceder() Los métodos desvincularán la transacción del hilo. Para citar del javadoc para ambos métodos:

Cuando se completa este método, el hilo ya no está asociado con una transacción.

Hay dos formas de lidiar con esto (y las estoy describiendo de una manera muy cruda que es posible que desee refinar un poco).

Opción 1: Emitir una reversión o un compromiso contra el administrador de transacciones (en un bloque de prueba porque fallará).

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { transactionManager.rollback(); } catch (Throwable t) {}
    service.deleteAccounts();
  }
}

Opción 2: Inicie una nueva transacción, que satisfará el atributo REQUERIDO de su EJB iniciando previamente una transacción, pero debe quedarse y administrarla, lo que se vuelve pegajoso.

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { 
      transactionManager.begin();
      service.deleteAccounts();
      transactionManager.commit();
    } catch (Exception e) {
        // ... handle exception here
    }
  }
}

Opción 3: la opción más limpia puede ser marcar el método EJB como REQUIRES_NEW ya que esto obligará al contenedor EJB a iniciar una nueva transacción.

Respondido 01 Feb 12, 18:02

Gracias Nicholas, para hacer las cosas más limpias, he decidido enviar un mensaje JMS que activará la próxima llamada EJB. - Yaniv Cohen

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.