¿Diferencia entre FETCHType LAZY y EAGER en Java Persistence API?

Soy un novato en Java Persistence API e Hibernate.

¿Cuál es la diferencia entre FetchType.LAZY y FetchType.EAGER en Java Persistence API?

A veces tienes dos entidades y existe una relación entre ellas. Por ejemplo, puede tener una entidad llamada Universidad y otra entidad llamada Estudiante.

La entidad de la Universidad puede tener algunas propiedades básicas como identificación, nombre, dirección, etc., así como una propiedad llamada estudiantes:

 public class University { private String id; private String name; private String address; private List students; // setters and getters } 

Ahora, cuando carga una Universidad desde la base de datos, JPA carga sus campos de id, nombre y dirección por usted. Pero tiene dos opciones para los estudiantes: cargarlo junto con el rest de los campos (es decir, ansiosamente) o cargarlo bajo demanda (es decir, de forma perezosa) cuando llama al método getStudents () de la universidad.

Cuando una universidad tiene muchos estudiantes, no es eficiente cargar a todos sus alumnos cuando no son necesarios. Por lo tanto, en casos similares, puede declarar que desea cargar a los estudiantes cuando realmente se necesitan. Esto se llama carga diferida.

Básicamente,

 LAZY = fetch when needed EAGER = fetch immediately 

EAGER carga de EAGER de las colecciones significa que se obtienen por completo en el momento en que se obtiene su padre. Por lo tanto, si tiene un Course y tiene una List , todos los estudiantes se obtienen de la base de datos en el momento en que se obtiene el Course .

LAZY por otro lado, significa que los contenidos de la List solo se obtienen cuando intenta acceder a ellos. Por ejemplo, llamando a course.getStudents().iterator() . Llamar a cualquier método de acceso en la List iniciará una llamada a la base de datos para recuperar los elementos. Esto se implementa creando un Proxy alrededor de la List (o Set ). Entonces, para sus colecciones perezosas, los tipos concretos no son ArrayList y HashSet , sino PersistentSet y PersistentList (o PersistentBag )

Puedo considerar el rendimiento y la utilización de la memoria. Una gran diferencia es que la estrategia de búsqueda de EAGER permite usar objetos de datos obtenidos sin sesión. ¿Por qué?
Todos los datos se obtienen cuando los datos marcados impacientes en el objeto cuando se conecta la sesión. Sin embargo, en el caso de una estrategia de carga diferida, el objeto marcado de carga diferida no recupera datos si la sesión se desconecta (después de la instrucción session.close() ). Todo lo que puede hacer el proxy de hibernación. La estrategia impaciente permite que los datos estén disponibles después de la sesión de cierre.

De forma predeterminada, para todos los objetos de colección y mapa, la regla de FetchType.LAZY es FetchType.LAZY y para otras instancias sigue la política FetchType.EAGER .
En resumen, @OneToMany y @ManyToMany relaciones no @ManyToMany los objetos relacionados (colección y mapa) implícitamente, pero la operación de recuperación se @OneToOne en cascada a través del campo en @OneToOne y @ManyToOne .

(cortesía de: – objectdbcom)

Según mi conocimiento, ambos tipos de búsqueda dependen de tu requerimiento.

FetchType.LAZY está bajo demanda (es decir, cuando requerimos los datos).

FetchType.EAGER es inmediato (es decir, antes de que surja nuestro requerimiento, estamos recolectando el registro innecesariamente)

Desde el Javadoc :

La estrategia EAGER es un requisito en el tiempo de ejecución del proveedor de persistencia de que los datos deben obtenerse con entusiasmo. La estrategia LAZY es una pista para el tiempo de ejecución del proveedor de persistencia de que los datos se deben buscar de forma perezosa cuando se accede por primera vez.

Por ejemplo, ansioso es más proactivo que perezoso. Lazy solo ocurre en el primer uso (si el proveedor toma la sugerencia), mientras que con las cosas ansiosas (puede) obtenerse previamente.

Tanto FetchType.LAZY como FetchType.EAGER se utilizan para definir el plan de recuperación predeterminado .

Desafortunadamente, solo puede anular el plan de recuperación predeterminado para la recuperación de LAZY. La búsqueda de EAGER es menos flexible y puede generar muchos problemas de rendimiento .

Mi consejo es restringir el impulso de hacer que tus asociaciones EAGER, porque ir a buscar es una responsabilidad en tiempo de consulta. Entonces, todas sus consultas deberían usar la directiva fetch para recuperar solo lo que sea necesario para el caso comercial actual.

El tipo Lazy Fetch es seleccionado de forma predeterminada por Hibernate a menos que Eager explícitamente el tipo de Eager expeditiva. Para ser más preciso y conciso, la diferencia puede establecerse a continuación.

FetchType.LAZY = Esto no carga las relaciones a menos que lo invoque mediante el método getter.

FetchType.EAGER = Esto carga todas las relaciones.

Pros y contras de estos dos tipos de búsqueda.

Lazy initialization mejora el rendimiento al evitar el cálculo innecesario y reducir los requisitos de memoria.

Eager initialization requiere más consumo de memoria y la velocidad de procesamiento es lenta.

Habiendo dicho eso, depende de la situación, cualquiera de estas inicializaciones puede ser utilizada.

Book.java

  import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="Books") public class Books implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="book_id") private int id; @Column(name="book_name") private String name; @Column(name="author_name") private String authorName; @ManyToOne Subject subject; public Subject getSubject() { return subject; } public void setSubject(Subject subject) { this.subject = subject; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthorName() { return authorName; } public void setAuthorName(String authorName) { this.authorName = authorName; } } 

Subject.java

  import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="Subject") public class Subject implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="subject_id") private int id; @Column(name="subject_name") private String name; /** Observe carefully i have mentioned fetchType.EAGER. By default its is fetchType.LAZY for @OneToMany i have mentioned it but not required. Check the Output by changing it to fetchType.EAGER */ @OneToMany(mappedBy="subject",cascade=CascadeType.ALL,fetch=FetchType.LAZY, orphanRemoval=true) List listBooks=new ArrayList(); public List getListBooks() { return listBooks; } public void setListBooks(List listBooks) { this.listBooks = listBooks; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 

HibernateUtil.java

 import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static SessionFactory sessionFactory ; static { Configuration configuration = new Configuration(); configuration.addAnnotatedClass (Com.OneToMany.Books.class); configuration.addAnnotatedClass (Com.OneToMany.Subject.class); configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver"); configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate"); configuration.setProperty("hibernate.connection.username", "root"); configuration.setProperty("hibernate.connection.password", "root"); configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect"); configuration.setProperty("hibernate.hbm2ddl.auto", "update"); configuration.setProperty("hibernate.show_sql", "true"); configuration.setProperty(" hibernate.connection.pool_size", "10"); configuration.setProperty(" hibernate.cache.use_second_level_cache", "true"); configuration.setProperty(" hibernate.cache.use_query_cache", "true"); configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider"); configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory"); // configuration StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()); sessionFactory = configuration.buildSessionFactory(builder.build()); } public static SessionFactory getSessionFactory() { return sessionFactory; } } 

Main.java

  import org.hibernate.Session; import org.hibernate.SessionFactory; public class Main { public static void main(String[] args) { SessionFactory factory=HibernateUtil.getSessionFactory(); save(factory); retrieve(factory); } private static void retrieve(SessionFactory factory) { Session session=factory.openSession(); try{ session.getTransaction().begin(); Subject subject=(Subject)session.get(Subject.class, 1); System.out.println("subject associated collection is loading lazily as @OneToMany is lazy loaded"); Books books=(Books)session.get(Books.class, 1); System.out.println("books associated collection is loading eagerly as by default @ManyToOne is Eagerly loaded"); /*Books b1=(Books)session.get(Books.class, new Integer(1)); Subject sub=session.get(Subject.class, 1); sub.getListBooks().remove(b1); session.save(sub); session.getTransaction().commit();*/ }catch(Exception e){ e.printStackTrace(); }finally{ session.close(); } } private static void save(SessionFactory factory){ Subject subject=new Subject(); subject.setName("C++"); Books books=new Books(); books.setAuthorName("Bala"); books.setName("C++ Book"); books.setSubject(subject); subject.getListBooks().add(books); Session session=factory.openSession(); try{ session.beginTransaction(); session.save(subject); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); }finally{ session.close(); } } } 

Compruebe el método de recuperación () de Main.java. Cuando obtenemos Subject, su lista de colecciones Books , anotada con @OneToMany , se cargará de forma perezosa. Pero, por otro lado, la asociación relacionada con Books of collection, anotada con @ManyToOne , se carga a gran velocidad (por [default][1] para @ManyToOne , fetchType=EAGER ). Podemos cambiar el comportamiento colocando fetchType.EAGER en @OneToMany Subject.java o fetchType.LAZY en @ManyToOne en Books.java.

public enum FetchType extends java.lang.Enum Define estrategias para recuperar datos de la base de datos. La estrategia EAGER es un requisito en el tiempo de ejecución del proveedor de persistencia de que los datos deben obtenerse con entusiasmo. La estrategia LAZY es una pista para el tiempo de ejecución del proveedor de persistencia de que los datos se deben buscar de forma perezosa cuando se accede por primera vez. La implementación está permitida para recuperar datos para los cuales se ha especificado la sugerencia de estrategia LAZY. Ejemplo: @Basic (fetch = LAZY) protegido String getName () {return name; }

Fuente

@ drop-shadow si está utilizando Hibernate, puede llamar a Hibernate.initialize() cuando invoque el método getStudents() :

 Public class UniversityDaoImpl extends GenericDaoHibernate implements UniversityDao { //... @Override public University get(final Integer id) { Query query = getQuery("from University u where idUniversity=:id").setParameter("id", id).setMaxResults(1).setFetchSize(1); University university = (University) query.uniqueResult(); ***Hibernate.initialize(university.getStudents());*** return university; } //... } 

LAZY: Capta las entidades secundarias perezosamente, es decir, en el momento de buscar la entidad padre, simplemente recupera el proxy (creado por cglib o cualquier otra utilidad) de las entidades hijo y cuando accede a cualquier propiedad de la entidad hijo, hibernate realmente la recupera.

EAGER: obtiene las entidades secundarias junto con el padre.

Para una mejor comprensión, vaya a la documentación de Jboss o puede usar hibernate.show_sql=true para su aplicación y verificar las consultas emitidas por hibernate.