example - ¿Diferencia entre FetchType LAZY y EAGER en la API de persistencia de Java?
lazy and eager in spring boot (13)
Soy un novato en Java Persistence API e Hibernate.
¿Cuál es la diferencia entre FetchType.LAZY
y FetchType.LAZY en la API de persistencia de Java?
enumeración pública FetchType extiende java.lang.Enum Define estrategias para obtener 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 se deben recuperar con entusiasmo. La estrategia LAZY es una sugerencia para el tiempo de ejecución del proveedor de persistencia de que los datos se deben buscar con pereza cuando se accede por primera vez. Se permite a la implementación recuperar con ansia los datos para los cuales se ha especificado la sugerencia de estrategia LAZY. Ejemplo: @Basic (fetch = LAZY) protegido String getName () {nombre de retorno; }
@ drop-shadow si está usando Hibernate, puede llamar a Hibernate.initialize()
cuando invoque el método getStudents()
:
Public class UniversityDaoImpl extends GenericDaoHibernate<University, Integer> 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;
}
//...
}
A veces tienes dos entidades y hay una relación entre ellas. Por ejemplo, podría tener una entidad llamada Universidad y otra entidad llamada Estudiante.
La entidad de la Universidad puede tener algunas propiedades básicas como id, nombre, dirección, etc., así como una propiedad llamada estudiantes:
public class University {
private String id;
private String name;
private String address;
private List<Student> students;
// setters and getters
}
Ahora, cuando carga una universidad desde la base de datos, JPA carga sus campos de identificación, nombre y dirección por usted. Pero tiene dos opciones para los estudiantes: cargarlo junto con el resto de los campos (es decir, con entusiasmo) o cargarlo a pedido (es decir, perezosamente) cuando llama al método getStudents () de la universidad.
Cuando una universidad tiene muchos estudiantes, no es eficiente cargar a todos sus estudiantes cuando no son necesarios. Por lo tanto, en casos similares, puede declarar que desea que los alumnos se carguen cuando realmente se necesiten. Esto se llama carga perezosa.
Básicamente,
LAZY = fetch when needed
EAGER = fetch immediately
De forma predeterminada, para todos los objetos de FetchType.LAZY
y FetchType.LAZY
regla de FetchType.LAZY
es FetchType.LAZY
y para otras instancias sigue la política de FetchType.EAGER
.
En resumen, las relaciones @OneToMany
y @ManyToMany
no recuperan los objetos relacionados (colección y mapa) de manera implícita, pero la operación de recuperación se realiza en cascada a través del campo en @OneToOne
y @ManyToOne
.
Desde el Javadoc :
La estrategia EAGER es un requisito en el tiempo de ejecución del proveedor de persistencia de que los datos se deben recuperar con entusiasmo. La estrategia LAZY es una sugerencia para el tiempo de ejecución del proveedor de persistencia de que los datos se deben buscar con pereza cuando se accede por primera vez.
Por ejemplo, ansioso es más proactivo que perezoso. La pereza solo ocurre en el primer uso (si el proveedor toma la sugerencia), mientras que con cosas ansiosas (puede) ser pre-buscada.
El tipo Lazy
Fetch se selecciona de forma predeterminada por Hibernate a menos que marque explícitamente el tipo Eager
Fetch. Para ser más precisos y concisos, la diferencia se puede establecer de la siguiente manera.
FetchType.LAZY
= Esto no carga las relaciones a menos que lo invoque a través del 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 cálculos innecesarios y reduce los requisitos de memoria.
Eager initialization
requiere más consumo de memoria y la velocidad de procesamiento es lenta.
Dicho esto, dependiendo de la situación, se puede utilizar cualquiera de estas dos inicializaciones.
LAZY: Obtiene las entidades hijas de manera perezosa, es decir, en el momento de buscar la entidad paterna, solo obtiene el proxy (creado por cglib o cualquier otra utilidad) de las entidades hijas y cuando accedes a cualquier propiedad de la entidad hijal, en realidad se recupera mediante hibernación.
EAGER: recupera las entidades hijas 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 verifique las consultas emitidas por la hibernación.
Puedo considerar el rendimiento y la utilización de la memoria. Una gran diferencia es que la estrategia de recuperación de EAGER permite utilizar objetos de datos recuperados sin sesión. ¿Por qué?
Todos los datos se recuperan cuando hay datos marcados en el objeto cuando la sesión está conectada. Sin embargo, en el caso de una estrategia de carga lenta, la carga lenta del objeto marcado no recupera datos si la sesión se desconecta (después de la declaración session.close()
). Todo lo que se puede hacer mediante hibernate proxy. La estrategia ansiosa permite que los datos sigan estando disponibles después de cerrar la sesión.
Según mi conocimiento, ambos tipos de búsqueda dependen de su requerimiento.
FetchType.LAZY
está en demanda (es decir, cuando requerimos los datos).
FetchType.EAGER
es inmediato (es decir, antes de que FetchType.EAGER
nuestros requisitos, estamos FetchType.EAGER
innecesariamente el registro)
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 LAZY. La recuperación de EAGER es menos flexible y puede llevar a muchos problemas de rendimiento .
Mi consejo es restringir la necesidad de hacer que sus asociaciones se conviertan en un EAGER, ya que la obtención de información es una responsabilidad de consulta. Por lo tanto, todas sus consultas deben usar la directiva de recuperación para recuperar solo lo que es necesario para el caso de negocio actual.
EAGER
carga de colecciones de EAGER
significa que se recuperan completamente en el momento en que se recuperan sus padres. Entonces, si tiene el Course
y tiene la List<Student>
, todos los estudiantes se recuperan de la base de datos en el momento en que se busca el Course
.
LAZY
por otro lado, significa que los contenidos de la List
se recuperan solo cuando intentas acceder a ellos. Por ejemplo, llamando a course.getStudents().iterator()
. Al llamar a cualquier método de acceso en la List
se iniciará una llamada a la base de datos para recuperar los elementos. Esto se implementa creando un Proxy alrededor de la List
(o Set
). Así que para sus colecciones perezosas, los tipos concretos no son ArrayList
y HashSet
, sino PersistentSet
y PersistentList
(o PersistentBag
)
Libro.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;
}
}
Asunto.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<Books> listBooks=new ArrayList<Books>();
public List<Books> getListBooks() {
return listBooks;
}
public void setListBooks(List<Books> 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 retrieve () de Main.java. Cuando obtengamos el Asunto, entonces su colección de libros de listas , anotada con @OneToMany
, se cargará perezosamente. Pero, por otro lado, la asociación de libros relacionada con el tema de la colección, anotada con @ManyToOne
, se carga con dificultad (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.