Pregunta

Tengo un apátrida bean algo como:

@Stateless
public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.SUPPORTED)
    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.process(obj);
        }
    }

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

Generalmente, el uso es, entonces, el cliente podría llamar processObjects(...), que en realidad no interactuar con el gerente de la entidad.Él hace lo que tiene que hacer y requiere proceso(...) de forma individual para cada objeto del proceso.La duración del proceso(...) es relativamente corto, pero processObjects(...) podría tomar un tiempo muy largo para ejecutar a través de todo.Por lo tanto no quiero mantener una transacción abierta.Yo ¿ necesita el proceso individual(...) las operaciones para operar dentro de sus propias transacciones.Esta debe ser una nueva transacción para cada llamada.Por último, me gustaría mantener la opción abierta para que el cliente llame proceso(...) directamente.

Yo he probado un número de diferentes tipos de transacciones:nunca, no se admite se admite (en processObjects) y requiere, requiere de nuevo (en proceso) pero me da TransactionRequiredException cada vez merge() es llamado.

He sido capaz de hacer que funcione mediante la división de los métodos en dos diferentes granos:

@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessBean2 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }
}

@Stateless
public class MyStatelessBean2 implements MyStatelessLocal2, MyStatelessRemote2 {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

pero todavía estoy curioso por saber si es posible realizar esto en una clase.A mí me parece que el administrador de transacciones sólo opera en el bean nivel, incluso cuando el individuo se presentan métodos más anotaciones específicas.Así que si me marca un método en una forma de evitar la transacción de partida de llamadas a otros métodos dentro de esa misma instancia, no crear una transacción, independientemente de cómo estén marcados?

Estoy usando el Servidor de Aplicaciones JBoss 4.2.1.GA, pero no respuestas específicas son bienvenidos / preferido.

¿Fue útil?

Solución

Otra manera de hacerlo es tener ambos métodos en la misma frijol y tener un @EJB referencia a sí mismo!Algo así como que:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

De esta manera usted realmente la 'fuerza' de la process() método que se accede a través de la ejb pila de proxies, por lo tanto, tomando el @TransactionAttribute en efecto - y todavía mantener una única clase.Ufff!

Otros consejos

Matt, la pregunta que uno se hace es bastante clásico, creo que la auto-solución de referencia por Herval/Pascal es limpio.Hay una solución más general que no se mencionan aquí.

Este es un caso para EJB "usuario" de las transacciones.Puesto que usted está en un bean de sesión que usted puede conseguir la transacción de usuario desde el contexto de la sesión.He aquí cómo el código se verá con transacciones de usuario:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {

    @Resource
    private SessionContext ctx;

    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    public void process(Object obj) {

        UserTransaction tx = ctx.getUserTransaction();

        tx.begin();

        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();

        tx.commit();
    }
}

Creo que la cosa está cada grano está envuelto en un proxy que controla el comportamiento transaccional.Cuando se llama desde un frijol a otro, usted va a través de que bean proxy y la transacción comportamiento puede ser cambiado por el proxy.

Pero cuando un bean llama a un método en sí mismo, con una diferente atributo de transacción, la llamada no ir a través del proxy, por lo que el comportamiento no cambia.

Matt, por lo que vale me ha llegado exactamente a la misma conclusión que tú.

TransactionAttributeTypes sólo se toman en consideración a la hora de cruzar Bean límites.Cuando se llama a los métodos dentro de la misma bean TransactionAttributeTypes no tienen ningún efecto, no importa lo que los Tipos se ponen en los métodos.

Por lo que puedo ver no hay nada en el EJB Persistencia de Especificaciones que especifica lo que el comportamiento debe ser bajo estas circunstancias.

También he tenido esta experiencia en Jboss.Yo también voy a dar una oportunidad en Glassfish y hacerle saber los resultados.

En caso de que alguien viene a través de este día:

para evitar dependencias circulares (que permite la auto referencia, por ejemplo) en JBoss utilizar la anotación 'IgnoreDependency", por ejemplo:

@IgnoreDependency @EJB Yo myselfRef;

Yo no lo he probado aún (estoy a punto), sino una alternativa a la inyección de una auto-referencia a través de la @EJB la anotación es el SessionContext.getBusinessObject() método.Esta sería otra manera de evitar la posibilidad de una referencia circular la voladura de las cosas que - aunque al menos para los apátridas, los frijoles de la inyección no parecen funcionar.

Estoy trabajando en un gran sistema en el que ambas técnicas son empleadas (presumiblemente por diferentes desarrolladores), pero no estoy seguro de cuál es la manera "correcta" de hacerlo.

Creo que tiene que ver con la @TransationAttribute(TransactionAttributeType.Nunca) en el método de processObjects.

TransactionAttributeType.Nunca

http://docs.sun.com/app/docs/doc/819-3669/6n5sg7cm3?a=view

Si el cliente se está ejecutando dentro de un de la transacción y se invoca la empresa bean método, el contenedor lanza un RemoteException.Si el cliente no es asociados con una transacción, el contenedor no se inicia una nueva la transacción antes de ejecutar el método.

Supongo que usted es el cliente el método processObjects desde el código de cliente.Porque, probablemente, su cliente no está relacionada con una transacción de la llamada al método con TransactionAttributeType.Nunca es feliz en el primer lugar.Luego llame a la proceso de método de processObjects que aunque tener el TransactionAttributeType.Se requiere la anotación no fue una judía llamada al método y la política de transacciones no es forzada.Cuando llame combinación de usted consigue la excepción debido a que aún no están asociados con una transacción.

Trate de usar TransactionAttributeType.Se requiere por tanto bean métodos para ver si se hace el truco.

Tenía estas circular de los problemas de dependencia que Kevin mencionado.Sin embargo, la propuesta de la anotación @IgnoreDependency es un jboss-anotación específica y no hay ninguna contraparte en el correo.g Glassfish.

Ya que no funciona con la configuración predeterminada del EJB referencia, me sentí un poco incómodo con esta solución.

Por lo tanto, me dio bluecarbon la solución de una oportunidad, comenzando así el interior de la transacción "a mano".

Junto a esto, veo que no hay solución, pero para implementar el proceso interno() en otro bean, el cual también es feo porque simplemente queremos molestar a nuestra clase modelo con este tipo de detalles técnicos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top