2011-09-01 15 views
9

En nuestra aplicación J2EE, utilizamos un bean stateful EJB-3 para permitir que el código frontal cree, modifique y guarde entidades persistentes (administradas a través de JPA-2).¿Por qué tenemos que enjuagar manualmente() el EntityManager en un PersistenceContext extendido?

se ve algo como esto:

@LocalBean 
@Stateful 
@TransactionAttribute(TransactionAttributeType.NEVER) 
public class MyEntityController implements Serializable 
{ 
    @PersistenceContext(type = PersistenceContextType.EXTENDED) 
    private EntityManager em; 

    private MyEntity current; 

    public void create() 
    { 
     this.current = new MyEntity(); 
     em.persist(this.current); 
    } 

    public void load(Long id) 
    { 
     this.current = em.find(MyEntity.class, id); 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    public void save() 
    { 
     em.flush(); 
    } 
} 

muy importante, para evitar demasiado pronto compromete, sólo el método save() está dentro de una transacción, por lo que si llamamos create(), insertamos nada en la base de datos.

Curiosamente, en el método save(), tenemos que llamar al em.flush() para llegar a la base de datos. De hecho, probé y descubrí que también podemos llamar al em.isOpen() o al em.getFlushMode(), y todo lo relacionado con "em".

No entiendo este punto. Como save() está en una transacción, pensé que al final del método, la transacción se confirmará y, por lo tanto, el administrador de entidad persistente se vació automáticamente. ¿Por qué tengo que vaciarlo manualmente?

Gracias, Xavier

+0

No es necesario 'flush()'. 'joinTransaction()' debería ser suficiente para guardar sus modificaciones en su método transaccional. –

Respuesta

7

Para ser directo y al metal, no habrá ningún objetos registrados por el EntityManager en cuestión hasta que realmente uso que en una transacción.

Nosotros, en aplicación de servidor de la tierra va a crear uno de estos objetos para hacer la flush() y registrarlo con el javax.transaction.TransactionSynchronizationRegistry o javax.transaction.Transaction. Esto no puede hacerse a menos que haya una transacción activa.

Eso es lo largo y lo corto.

Sí, un servidor de aplicaciones podría muy bien mantener una lista de los recursos que le dio al bean con estado y autoinscribirlos en cada transacción que el bean con estado podría iniciar o participar. La desventaja de eso es que usted pierde completamente la capacidad de decidir qué cosas van en qué transacciones. Tal vez tenga 2 o 3 transacciones diferentes para ejecutar en diferentes unidades de persistencia y agregue el trabajo en su contexto de persistencia extendida para una transacción muy específica. Es realmente un problema de diseño y el servidor de aplicaciones debería dejar esas decisiones a la aplicación en sí.

Lo utiliza en una transacción y lo inscribiremos en la transacción. Ese es el contrato básico.

Nota al margen, dependiendo de cómo se maneja el EntityManager subyacente, cualquier llamada permanente a la EntityManager puede ser suficiente para causar una descarga completa al final de la transacción. Ciertamente, flush() es el más directo y claro, pero un persist() o incluso un find() podría hacerlo.

+1

Wooh, me tomó algo de tiempo entender completamente tu respuesta, pero ahora tiene sentido. ¡Gracias! –

+0

Cita relevante de la especificación JPA2.1 (7.6.4.1 Requisitos para la propagación de contexto de persistencia) para el contexto de persistencia no propagado : 'Si se invoca el administrador de entidad dentro de una transacción JTA, el contexto de persistencia se asociará a la transacción JTA '. –

0

Si utiliza contexto de persistencia extendido sobre todas las operaciones realizadas dentro de entidades gestionadas métodos no transaccionales se ponen en cola para escribirse en la base de datos. Una vez que llame a flush() en el administrador de entidades dentro de un contexto de transacción, todos los cambios en cola se escriben en la base de datos. Entonces, en otras palabras, el hecho de que tenga un método transaccional no compromete los cambios en sí mismo cuando el método sale (como en CMT), pero el administrador de entidad de enjuague en realidad lo hace. Se puede encontrar una explicación completa de este proceso here

+2

Vi este tutorial, pero parece un poco confuso. Dice "Esto significa que cualquier método de persistencia, fusión o eliminación que llame en realidad no dará como resultado una ejecución JDBC y, por lo tanto, una actualización de la base de datos hasta que llame manualmente a EntityManager.flush". Punto para ti :) Pero en el segundo ejemplo, dice que "never() la actualización se confirmará al final del método de pago()", y este pago() está vacío, sin ningún color. ¿Cómo puedes explicar este ejemplo? Además, en los patrones Realworld JavaEE de Adam Bien, el patrón GateWay también tiene un método de guardado vacío: http://tinyurl.com/3o96xoh (diapositiva 67). –

0

Porque no hay forma de saber "cuándo" el cliente finaliza la sesión (alcance ampliado).

Cuestiones relacionadas