Hibernate: diferencia entre session.get y session.load


88

Desde la API, pude ver que tiene algo que ver con el proxy. Pero no pude encontrar mucha información sobre el proxy y no entiendo la diferencia entre llamar session.gety session.load. ¿Podría alguien explicarme o dirigirme a una página de referencia?

¡¡Gracias!!

Respuestas:


117

Desde el foro de Hibernate :

Esto del libro Hibernate in Action. Bueno, lee esto ..


Recuperar objetos por identificador El siguiente fragmento de código de Hibernate recupera un objeto Usuario de la base de datos:

User user = (User) session.get(User.class, userID);

El método get () es especial porque el identificador identifica de forma única una sola instancia de una clase. Por lo tanto, es común que las aplicaciones usen el identificador como un identificador conveniente para un objeto persistente. La recuperación por identificador puede usar el caché al recuperar un objeto, evitando un acierto en la base de datos si el objeto ya está en caché. Hibernate también proporciona un método load ():

User user = (User) session.load(User.class, userID);

El método load () es más antiguo; get () se agregó a la API de Hibernate debido a la solicitud del usuario. La diferencia es trivial:

Si load () no puede encontrar el objeto en la caché o la base de datos, se lanza una excepción. El método load () nunca devuelve nulo. El método get () devuelve un valor nulo si no se puede encontrar el objeto.

El método load () puede devolver un proxy en lugar de una instancia persistente real. Un proxy es un marcador de posición que activa la carga del objeto real cuando se accede a él por primera vez; Por otro lado, get () nunca devuelve un proxy. Elegir entre get () y load () es fácil: si está seguro de que el objeto persistente existe y la inexistencia se consideraría excepcional, load () es una buena opción. Si no está seguro de que haya una instancia persistente con el identificador dado, use get () y pruebe el valor de retorno para ver si es nulo. El uso de load () tiene una implicación adicional: la aplicación puede recuperar una referencia válida (un proxy) a una instancia persistente sin llegar a la base de datos para recuperar su estado persistente. Por lo tanto, load () podría no lanzar una excepción cuando no encuentre el objeto persistente en la caché o la base de datos; la excepción se lanzaría más tarde, cuando se acceda al proxy. Por supuesto, recuperar un objeto por identificador no es tan flexible como usar consultas arbitrarias.


1
Estoy depurando un problema en este momento donde session.Get <T> () está devolviendo un proxy.
Kent Boogaart

7
¡Muchas gracias! La parte monetaria para mí fue: "Si load () no puede encontrar el objeto en la caché o en la base de datos, se lanza una excepción. El método get () devuelve nulo si no se puede encontrar el objeto".
Chris

15
El JavaDoc para Session.get dice: Devuelve la instancia persistente de la clase de entidad dada con el identificador dado, o nulo si no existe tal instancia persistente. (Si la instancia, o un proxy para la instancia, ya está asociado con la sesión, devuelve esa instancia o proxy). Entonces, la sección del libro que dice: "Por otro lado, get () nunca devuelve un proxy". no es correcto.
Vicky

si está utilizando una estrategia de gestión de transacciones con sus daos, es posible que prefiera get (). de lo contrario, la persona que llama también deberá estar ejecutando en el contexto de una sesión de hibernación abierta en caso de que load () devuelva un proxy. por ejemplo, si está haciendo MVC, su controlador puede ejecutar dao.load () y luego lanzar una excepción al intentar acceder al objeto proxy más tarde si no hay una sesión válida. hacer dao.get () devolverá el objeto real al controlador independientemente de la sesión (suponiendo que exista)
dev

El problema que describió @Vicky puede causar dolores de cabeza, y no veo ninguna ventaja en ello. En algunos casos, también necesito el identificador para más consultas parametrizadas. Pero como un proxy del objeto ya está en la sesión, el captador del identificador devuelve nulo. ¿Por qué recuperan el proxy en lugar de la instancia real si ese proxy está en la sesión?
djmj

15

Bueno, al menos en nhibernate, session.Get (id) cargará el objeto desde la base de datos, mientras que session.Load (id) solo crea un objeto proxy sin salir de su servidor. Funciona como cualquier otra propiedad de carga diferida en sus POCO (o POJO :). A continuación, puede utilizar este proxy como referencia al propio objeto para crear relaciones, etc.

Piense en ello como tener un objeto que solo conserva el Id y que cargará el resto si alguna vez lo necesita. Si solo lo está pasando para crear relaciones (como FK), la identificación es todo lo que necesitará.


Entonces, ¿quiere decir que load (id) primero llegará a la base de datos para verificar si es una identificación válida o no y luego devolverá el objeto proxy y cuando se acceda a las propiedades de este objeto, volverá a la base de datos? ¿No es un escenario improbable? dos consultas para cargar un solo objeto?
faisalbhagat

No, load (id) no validará la identificación en absoluto, por lo que no hay viajes de ida y vuelta a la base de datos. Úselo solo cuando esté seguro de que es válido.
Jorge Alves

9

session.load () siempre devolverá un "proxy" (término de Hibernación) sin llegar a la base de datos. En Hibernate, el proxy es un objeto con el valor de identificador dado, sus propiedades aún no se han inicializado, simplemente parece un objeto falso temporal. Si no se encuentra ninguna fila, arrojará una ObjectNotFoundException.

session.get () siempre golpea la base de datos y devuelve el objeto real, un objeto que representa la fila de la base de datos, no el proxy. Si no se encuentra ninguna fila, devuelve nulo.

El rendimiento con estos métodos también marca diferencias. entre dos...


3

Un punto extra más:

El método get de la clase Hibernate Session devuelve un valor nulo si el objeto no se encuentra en la caché ni en la base de datos. while load () método arroja ObjectNotFoundException si el objeto no se encuentra en la caché ni en la base de datos, pero nunca devuelve un valor nulo.


2

Una consecuencia indirecta de usar "cargar" en lugar de "obtener" es que el bloqueo optimista usando un atributo de versión puede no funcionar como cabría esperar. Si una carga simplemente crea un proxy y no lee de la base de datos, la propiedad de la versión no se carga. La versión solo se cargará cuando / si posteriormente hace referencia a una propiedad del objeto, lo que activa una selección. Mientras tanto, otra sesión puede actualizar el objeto y su sesión no tendrá la versión original que necesita para realizar la comprobación de bloqueo optimista, por lo que la actualización de su sesión sobrescribirá la actualización de la otra sesión sin previo aviso.

Aquí hay un intento de esbozar este escenario con dos sesiones trabajando con un objeto con el mismo identificador. La versión inicial del objeto en la base de datos es 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

De hecho, queremos que la confirmación de la sesión 1 falle con una excepción de bloqueo optimista, pero tendrá éxito aquí.

El uso de "get" en lugar de "load" soluciona el problema, porque get emitirá inmediatamente una selección y los números de versión se cargarán en los momentos correctos para la comprobación de bloqueo optimista.


0

También debemos tener cuidado al usar load, ya que lanzará una excepción si el objeto no está presente. Tenemos que usarlo solo cuando estamos seguros de que el objeto existe.


0

Una excelente explicación se encuentra en http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
Siempre devolverá un "proxy" (término de Hibernate) sin golpeando la base de datos.
En Hibernate, el proxy es un objeto con el valor de identificador dado, sus propiedades aún no se han inicializado, simplemente parece un objeto falso temporal.
Siempre devolverá un objeto proxy con el valor de identidad dado, incluso el valor de identidad no existe en la base de datos. Sin embargo, cuando intente inicializar un proxy recuperando sus propiedades de la base de datos, llegará a la base de datos con la instrucción select. Si no se encuentra ninguna fila, se lanzará una ObjectNotFoundException.
session.get ():
Siempre llega a la base de datos (si no se encuentra en la caché) y devuelve el objeto real, un objeto que representa la fila de la base de datos, no el proxy.
Si no se encuentra ninguna fila, devuelve nulo.


0

load () no puede encontrar el objeto de la caché o la base de datos, se lanza una excepción y el método load () nunca devuelve nulo.

El método get () devuelve un valor nulo si no se puede encontrar el objeto. El método load () puede devolver un proxy en lugar de una instancia persistente real get () nunca devuelve un proxy.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.