¿Qué es la carga diferida en Hibernate?

178

¿Qué es la carga diferida en Java? No entiendo el proceso. ¿Alguien puede ayudarme a comprender el proceso de carga diferida?

balancín
fuente

Respuestas:

268

Digamos que tienes un padre y ese padre tiene una colección de hijos. Hibernate ahora puede "cargar de forma diferida" a los hijos, lo que significa que en realidad no carga a todos los hijos al cargar el padre. En cambio, los carga cuando se le solicita que lo haga. Puede solicitarlo explícitamente o, y esto es mucho más común, hibernate los cargará automáticamente cuando intente acceder a un hijo.

La carga diferida puede ayudar a mejorar significativamente el rendimiento, ya que a menudo no necesitará a los niños y, por lo tanto, no se cargarán.

También tenga cuidado con el problema n + 1. Hibernate en realidad no cargará a todos los niños cuando acceda a la colección. En cambio, cargará a cada niño individualmente. Al iterar sobre la colección, esto provoca una consulta para cada hijo. Para evitar esto, puede engañar a Hibernate para que cargue a todos los hijos simultáneamente, por ejemplo, llamando a parent.getChildren (). Size ().

Thomas Lötzer
fuente
55
Alternativamente, se debe usar Hibernate.initialize (parent.getChildren ())
HakunaMatata
18
La afirmación "cuando accede a la colección ... cargará a cada niño individualmente" en realidad es completamente inexacta. En realidad es exactamente lo contrario. Cualquier desreferencia de parent.getChildren () hará que Hibernate cargue a todos los elementos secundarios de la colección en una consulta de base de datos. A menos que haya utilizado la muy especial sugerencia de "carga extra vaga". O a menos que guarde en caché la colección en el caché de segundo nivel y los elementos secundarios asociados también no se almacenen en caché.
Steve Ebersole
Oh, desbordamiento de pila: la mejor respuesta se encuentra al final de la página ;-)
Piotrek Hryciuk
76

"Carga diferida" significa que una entidad se cargará solo cuando realmente acceda a la entidad por primera vez.

El patrón es así:

public Entity getEntity() {
    if (entity == null) {
        entity = loadEntity();
    }
    return entity;
}

Esto ahorra el costo de precargar / rellenar previamente todas las entidades en un gran conjunto de datos, mientras que, después de todo, en realidad no las necesita todas .

En Hibernate, puede configurarlo para cargar perezosamente una colección de entidades secundarias. La carga diferida real se realiza dentro de los métodos PersistentSetque Hibernate usa "debajo de las campanas" para asignar la colección de entidades como Set.

P.ej

public class Parent {
    private Set<Child> children;

    public Set<Child> getChildren() {
        return children;
    }
}

.

public void doSomething() {
    Set<Child> children = parent.getChildren(); // Still contains nothing.

    // Whenever you call one of the following (indirectly), 
    // Hibernate will start to actually load and fill the set.
    children.size();
    children.iterator();
}
BalusC
fuente
25

Martin Fowler define el patrón de carga diferida en los patrones de la arquitectura de aplicaciones empresariales como tal:

Un objeto que no contiene todos los datos que necesita pero que sabe cómo obtenerlos.

Por lo tanto, al cargar un objeto determinado, la idea es no cargar con ansia los objetos relacionados que no puede usar de inmediato para ahorrar el costo de rendimiento relacionado. En cambio, los objetos relacionados se cargarán solo cuando se usen.

Este no es un patrón específico para el acceso a datos e Hibernate, pero es particularmente útil en tales campos e Hibernate admite la carga diferida de asociaciones de uno a muchos y asociaciones de punto único (uno a uno y muchos a uno) también bajo ciertas condiciones. La interacción perezosa se analiza con más detalle en el Capítulo 19 de la Documentación de referencia de Hibernate 3.0.

Pascal Thivent
fuente
15

La carga diferida predeterminada es verdadera. La carga diferida significa que cuando se ejecuta la consulta de selección, no llegará a la base de datos. Esperará la función getter, es decir, cuando lo necesitemos, buscará desde la base de datos. por ejemplo: usted es un padre que tiene un niño con muchos juguetes. Pero el problema actual es que cada vez que lo llamas (asumimos que tienes un niño), él viene a ti con todos sus juguetes también. Ahora, este es un problema, ya que no quieres que lleve sus juguetes todo el tiempo. Siendo el padre racional, sigue adelante y define los juguetes del niño como LAZY. Ahora, cuando lo llamas, él viene a ti sin sus juguetes.

Chandresh Solanki
fuente
11

La recuperación diferida decide si cargar objetos secundarios mientras se carga el objeto primario. Debe hacer esta configuración del archivo de mapeo de hibernación respectivo de la clase principal. Lazy = true(significa no cargar hijos) Por defecto, la carga diferida de los objetos hijos es verdadera.

Esto asegura que los objetos secundarios no se carguen a menos que se invoquen explícitamente en la aplicación llamando al getChild()método en el elemento getChild()primario.

Pero en algunos casos es necesario cargar los objetos secundarios cuando se carga el primario. Simplemente haga que lazy = false e hibernate cargue al niño cuando el padre se cargue desde la base de datos.

Ejemplo: si tienes una TABLA? EMPLEADO asignado al objeto Empleado y contiene un conjunto de objetos de Dirección. Clase principal: clase de empleado, clase secundaria: clase de dirección

public class Employee { 
private Set address = new HashSet(); // contains set of child Address objects 
public Set getAddress () { 
return address; 
} 
public void setAddresss(Set address) { 
this. address = address; 
} 
} 

En el archivo Employee.hbm.xml

<set name="address" inverse="true" cascade="delete" lazy="false"> 
<key column="a_id" /> 
<one-to-many class="beans Address"/> 
</set> 

En la configuración anterior. Si lazy="false": - cuando carga el objeto Empleado, la dirección del objeto secundario también se carga y se establece en el método setAddresss (). Si llama a employee.getAdress (), los datos cargados se devuelven. No hay una nueva llamada a la base de datos.

Si lazy="true": - Esta es la configuración predeterminada. Si no lo menciona, hibernate considere lazy = true. cuando carga el objeto Empleado en ese momento, no se carga la dirección del objeto hijo. Necesita una llamada adicional a la base de datos para obtener objetos de dirección. Si llama, employee.getAdress()entonces la consulta de la base de datos de tiempos se activa y devuelve resultados. Nueva base de datos de llamadas.

Bhavin Shah
fuente
Empleado y dirección no tienen relación padre-hijo en este escenario. ¡Es una relación 'tiene-a' !
Ram
Esto es agregación, no herencia.
Rishi
11

En lenguaje sencillo, es como si estuvieras haciendo un pastel y necesitarás 5-10 ingredientes del refrigerador. Tiene dos opciones: obtener todos los ingredientes del refrigerador y ponerlos en la plataforma de su cocina, o traer el artículo que desee cuando lo necesite.

Del mismo modo, en la carga ansiosa, obtiene toda la información sobre el frijol y sus clases relacionadas (no es una relación infantil o is-a pero tiene una relación, es decir, el pastel tiene harina, leche, crema, etc.), y en caso de carga diferida, primero solo trae su identificador y valores que provienen de la misma tabla (ingredientes necesarios que primero necesitará en su tazón en caso de pastel). Toda la información que provenga de otras tablas se obtendrá cuando sea necesario / utilizado.

Keyur
fuente
8

¿Carga lenta? Bueno, simplemente significa que los registros secundarios no se obtienen de inmediato, sino automáticamente tan pronto como intentas acceder a ellos.

Steffen
fuente
3

La configuración diferida decide si se deben cargar objetos secundarios mientras se carga el objeto primario. Debe hacer esta configuración en el archivo de mapeo de hibernación respectivo de la clase primaria. . Esto asegura que los objetos secundarios no se carguen a menos que se invoquen explícitamente en la aplicación llamando al método getChild () en parent. objeto. Pero en algunos casos es necesario cargar los objetos secundarios cuando se carga el primario. Simplemente haga que lazy = false e hibernate cargue el elemento secundario cuando se carga el elemento primario de la base de datos.

Siva Chimpiri
fuente
3

La carga diferida le permite diferir la recuperación de la asociación o tener un mejor control sobre la estrategia de recuperación.

Cuando utiliza la carga EAGER, define un plan de recuperación global que no se puede anular en el momento de la consulta, lo que significa que está limitado a una decisión que tomó al diseñar su modelo de entidad. La recuperación de EAGER es un olor a código , porque la estrategia de recuperación es una política de tiempo de consulta y puede diferir de un caso de uso comercial a otro.

La estrategia de recuperación es un aspecto muy importante, ya que demasiada recuperación de EAGER puede causar serios problemas relacionados con el rendimiento.

Vlad Mihalcea
fuente
2

La carga diferida es un patrón de diseño comúnmente utilizado en la programación de computadoras para diferir la inicialización de un objeto hasta el punto en el que se necesita. Puede contribuir a la eficiencia en la operación del programa si se usa de manera adecuada

Wikipedia

Enlace de Lazy Loading de hibernate.org

Diego Dias
fuente
1

Bueno, simplemente significa cargar los datos que necesita actualmente en lugar de cargar un montón de datos a la vez que no usará ahora. De este modo, el tiempo de carga de la aplicación es más rápido de lo habitual.

Abhinaya Pandey
fuente
0

Hiberante admite la función de inicialización diferida tanto para entidades como para colecciones. El motor de Hibernate solo carga aquellos objetos que estamos buscando, no otras entidades o colecciones.

lazy = "false" de forma predeterminada, la mención de inicialización de carga para el único elemento secundario es lazy.

abburi
fuente
0

La configuración diferida decide si se deben cargar objetos secundarios mientras se carga el objeto primario. Debe hacer esta configuración en el archivo de mapeo de hibernación respectivo de la clase primaria. .

Manikandan Adhimoolam
fuente
0

Sorprendentemente, ninguna de las respuestas habla sobre cómo se logra hibernando detrás de las pantallas.

La carga diferida es un patrón de diseño que se usa efectivamente en hibernación por razones de rendimiento que implica seguir las técnicas.


1. Instrumentación del código de bytes :

Mejora la definición de la clase base con ganchos de hibernación para interceptar todas las llamadas a ese objeto de entidad.

Hecho ya sea en tiempo de compilación o tiempo de ejecución [carga]

1.1 Tiempo de compilación

  • Operación posterior al tiempo de compilación

  • Principalmente por complementos maven / ant

1.2 Tiempo de ejecución

  • Si no se realiza la instrumentación en tiempo de compilación, se crea en tiempo de ejecución Utilizando bibliotecas como javassist

2. Proxies

El objeto de entidad que devuelve Hibernate es un proxy del tipo real.

Ver también: Javassist. ¿Cuál es la idea principal y dónde uso real?

Sankarganesh Eswaran
fuente