¿Debería cerrarse JPA Entity Manager?

82

Tengo el método a continuación.

public Profile readUser(String email){
    EntityManager em = EMF.get().createEntityManager();
    return em.find(Profile.class, email);
}

¿Está bien el uso anterior del administrador de entidades? ¿O es necesario cerrarlos? Alguna sugerencia por favor.

JR Galia
fuente
No simplemente no. A menos que quieras filtraciones ...

Respuestas:

131

Supongo que la respuesta es: depende .

Su administrador de entidad es la clave para obtener acceso al contexto donde residen las entidades. Si su aplicación es una aplicación JSE, debe considerar cuál es la esperanza de vida de su contexto.

Consideremos que creará un administrador de entidad por solicitud del usuario. Por lo tanto, mientras atiende una solicitud determinada, mantendrá abierto el administrador de su entidad y, cuando termine con él, lo cerrará.

En una aplicación JSE, es posible que haya considerado que le gustaría mantener abierto el administrador de su entidad durante toda la vida útil de la aplicación (suponiendo que no esté tratando con grandes cantidades de datos) y luego lo cierra cuando se cierra la aplicación.

En pocas palabras, cuándo lo abres y cuándo cierras depende completamente de tu estrategia y tu diseño. Lo cierra cuando ya no necesita las entidades en su contexto.

En su ejemplo, eso no es evidente, pero como está creando el EM en el método, debe cerrarlo antes de regresar; de lo contrario, ya no tendrá acceso a él nuevamente (a menos que lo mantenga en algún registro, que no es evidente en el código).

Si no lo cierra, sus entidades se mantendrán como adjuntas, incluso después de que haya terminado de usarlas. Su contexto se mantendrá vivo incluso cuando ya no pueda acceder a su EM.

La especificación JPA contiene más detalles. En la sección 7.7 Contextos de persistencia administrados por aplicaciones , dice:

Cuando se utiliza un gestor de entidades gestionado por la aplicación, la aplicación interactúa directamente con la fábrica de gestores de entidades del proveedor de persistencia para gestionar el ciclo de vida del gestor de entidades y para obtener y destruir contextos de persistencia.

Todos estos contextos de persistencia gestionados por aplicaciones tienen un alcance ampliado y pueden abarcar varias transacciones.

El EntityManagerFactory.createEntityManagermétodo y los métodos EntityManager closey isOpense utilizan para gestionar el ciclo de vida de un administrador de entidad gestionado por aplicación y su contexto de persistencia asociado.

El contexto de persistencia extendida existe desde el punto en el que se creó EntityManagerFactory.createEntityManagerel administrador de la entidad usando hasta que el administrador de la entidad se cierra mediante EntityManager.close.

Un contexto de persistencia ampliado obtenido del administrador de entidad gestionada por la aplicación es un contexto de persistencia autónomo que no se propaga con la transacción.

[...] El EntityManager.closemétodo cierra un administrador de entidad para liberar su contexto de persistencia y otros recursos. Después de llamar a close, la aplicación no debe invocar ningún método adicional en la EntityManagerinstancia, excepto getTransactiony isOpen, o se IllegalStateExceptionlanzará. Si se invoca el método de cierre cuando una transacción está activa, el contexto de persistencia permanece administrado hasta que se completa la transacción.

El EntityManager.isOpenmétodo indica si el administrador de la entidad está abierto. El isOpenmétodo devuelve verdadero hasta que se cierra el administrador de la entidad. Para comprender realmente cómo funciona esto, es vital comprender la relación entre el administrador de la entidad y el contexto.

Entonces, como puede ver, el administrador de entidades es la interfaz pública a través de la cual accede a sus entidades, sin embargo, sus entidades residen en un contexto, adjunto a su administrador de entidades. Comprender el ciclo de vida de los diferentes tipos de contextos responderá a su pregunta.

Los contextos de persistencia pueden ser de diferentes tipos. En las aplicaciones Java EE, puede tener un contexto de persistencia con alcance de transacción o un contexto de persistencia extendida . En la aplicación JSE, el desarrollador controla la naturaleza del contexto .

Cuando le solicita una entidad a su administrador de entidades, busca la entidad en su contexto adjunto, si encuentra la entidad allí, la devuelve, de lo contrario, recupera la entidad de la base de datos. Las llamadas posteriores para esta entidad en contexto devolverán la misma entidad.

Con alcance de transacción

En una aplicación Java EE que usa el contexto de persistencia de alcance de transacción, cuando accede por primera vez a su administrador de entidad, verifica si la transacción JTA actual tiene un contexto adjunto si aún no hay contexto presente, se crea un nuevo contexto y el administrador de entidad está vinculado a este contexto. Luego, la entidad se lee de la base de datos (o del caché si está presente) y se coloca en el contexto. Cuando su transacción finaliza (confirmar o deshacer), el contexto deja de ser válido y las entidades que contiene se separan. Este es el escenario clásico para los beans de sesiones sin estado.

@PersistenceContext(unitName="EmplService")
EntityManager em;

Esto también significa que, dependiendo de cómo diseñe sus transacciones, puede terminar con más de un contexto.

Contexto de persistencia extendida

En una aplicación Java EE con beans de sesión con estado, es posible que desee que el contexto sobreviva a múltiples invocaciones de beans, ya que no le gusta comprometerse hasta que el bean se haya marcado para su eliminación, ¿verdad? En esos casos, debe utilizar un contexto de persistencia extendido. En este caso, el contexto de persistencia se crea cuando se necesita por primera vez, pero no dejará de ser válido hasta que marque el bean con estado para su eliminación.

@PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)

Esto significa que, independientemente de la instancia del administrador de entidades que se inyecte en este bean en llamadas posteriores de los métodos de beans de sesión con estado, puede estar seguro de que siempre accederá al mismo contexto y, por lo tanto, incluso las llamadas posteriores devolverán el mismo ejemplo, porque es el mismo contexto.

Además, sus cambios no se eliminarán hasta que el bean esté marcado para su eliminación o los elimine manualmente.

Administrado por aplicación

Siempre puede crear una instancia manual de la fábrica de su administrador de entidad y su administrador de entidad. Esto es lo que normalmente haría en una aplicación JSE, ¿verdad?

Para este tipo de aplicaciones, normalmente no tiene un contenedor para manejar las transacciones JTA, ¿verdad? Por lo tanto, utiliza transacciones locales de recursos y es responsable de confirmar o revertir manualmente los cambios.

Para este tipo de aplicación, cuando crea una instancia de su administrador de entidad, se le adjunta automáticamente un contexto.

Dependiendo de su aplicación, puede decidir crear un administrador de entidad global cuyo ciclo de vida esté vinculado a la vida de la aplicación en sí. Es un administrador de entidad única durante toda la vida útil de la aplicación. En estos casos, su contexto se creará y destruirá con su administrador de entidad.

O bien, puede crear un administrador de entidad por conversación (es decir, transacción) con el usuario de su aplicación. El alcance, en este caso, lo determina usted, pero aún así, su contexto será creado y destruido con su administrador de entidad.

Edwin Dalorzo
fuente
Excelente respuesta, pero necesito saberlo: abrir y cerrar EntityManager varias veces durante una sesión tiene un alto costo de rendimiento. Crear instancias y cerrar solo una vez, o instanciar / usar / cerrar en cada operación de base de datos cruda, ¿cuál es el mejor enfoque? "depende" ok, pero debe tener un uso más adecuado para la mayoría de los casos de uso ..
Tomrlh
4
@tomurlh En lo que a mí respecta, el costo de creación EntityManagerdebe ser insignificante. Desde mi punto de vista, EntityManager es solo una abstracción para tratar la unidad de trabajo de la transacción actual. Creo que está perfectamente bien crear y destruir uno por transacción. Ahora, tiene otras implicaciones, porque los EntityManagerservidores como un caché transaccional para sus entidades y, por lo tanto, tener un alcance de transacción bien definido y tratar adecuadamente con las entidades podría aprovechar este caché.
Edwin Dalorzo
El método EntityManager.close cierra un administrador de entidad para liberar su contexto de persistencia. ¿Qué es un contexto de persistencia?
gstackoverflow
Esto también significa que, dependiendo de cómo diseñe sus transacciones, puede terminar con más de un contexto. ¿Podrías explicar cómo?
gstackoverflow