Pregunta

Soy un novato en Java Persistence API y Hibernate.

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

¿Fue útil?

Solución

A veces tienes dos entidades y hay una relación entre ellas. Por ejemplo, es posible que se le llame una entidad llamada University y otra entidad llamada Student Y una universidad podría tener muchos estudiantes:

La entidad universitaria puede tener algunas propiedades básicas como ID, nombre, dirección, etc., así como una propiedad de recolección llamada estudiantes que devuelve la lista de estudiantes para una universidad determinada:

A university has many students

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 su ID, nombre y campos de dirección para usted. Pero tiene dos opciones sobre cómo se deben cargar los estudiantes:

  1. Cargarlo junto con el resto de los campos (es decir, ansiosamente), o
  2. Para cargarlo a pedido (es decir, perezosamente) cuando llamas a la universidad getStudents() método.

Cuando una universidad tiene muchos estudiantes, no es eficiente cargar a todos sus estudiantes junto con ella, especialmente cuando no son necesarios y, en casos, puede declarar que desea que los estudiantes se carguen cuando realmente sean necesarios. Esto se llama carga perezosa.

Aquí hay un ejemplo, donde students está explícitamente marcado para ser cargado con entusiasmo:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Student> students;

    // etc.    
}

Y aquí hay un ejemplo donde students está explícitamente marcado para cargar perezosamente:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Student> students;

    // etc.
}

Otros consejos

Básicamente,

LAZY = fetch when needed
EAGER = fetch immediately

EAGER La carga de colecciones significa que se obtienen completamente en el momento en que sus padres son recortados. Entonces si tienes Course y tiene List<Student>, todos los estudiantes son recogidos de la base de datos en ese momento el Course es recogido.

LAZY por otro lado significa que el contenido del List se obtienen solo cuando intentas acceder a ellos. Por ejemplo, llamando course.getStudents().iterator(). Llamando a cualquier método de acceso en el List iniciará una llamada a la base de datos para recuperar los elementos. Esto se implementa creando un proxy en torno al List (o Set). Entonces, para sus colecciones perezosas, los tipos de concreto no son ArrayList y HashSet, pero 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 ansiosa permite usar el objeto de datos recuperado sin sesión. ¿Por qué?
Todos los datos se obtienen cuando están ansiosos datos marcados en el objeto cuando la sesión está conectada. Sin embargo, en el caso de la estrategia de carga perezosa, el objeto marcado de carga perezosa no recupera los datos si la sesión está desconectada (después session.close() declaración). Todo lo que se puede hacer por proxy hibernado. La estrategia ansiosa permite que los datos sigan disponibles después de la sesión de cierre.

Por defecto, para todos los objetos de colección y mapa, la regla de recuperación es FetchType.LAZY y para otros casos sigue el FetchType.EAGER política.
En breve, @OneToMany y @ManyToMany Las relaciones no obtienen los objetos relacionados (colección y mapa) implícitamente, pero la operación de recuperación se cascan a través del campo en @OneToOne y @ManyToOne unos.

(Cortesía:- ObjectDBCom)

Según mi conocimiento, ambos tipo de búsqueda depende de su requisito.

FetchType.LAZY está a pedido (es decir, cuando requerimos los datos).

FetchType.EAGER es inmediato (es decir, antes de que llegue nuestro requisito, estamos obteniendo innecesariamente el registro)

Ambas cosas FetchType.LAZY y FetchType.EAGER se utilizan para definir el Plan de búsqueda predeterminado.

Desafortunadamente, solo puede anular el plan de recuperación predeterminado para la obtención de fisos. La búsqueda ansiosa es menos flexible y puede conducir a muchos problemas de rendimiento.

Mi consejo es restringir el impulso de hacer que sus asociaciones tengan ansiosos porque buscar es una responsabilidad de tiempo de consulta. Entonces todas sus consultas deben usar el buscar Directiva para recuperar solo lo que es necesario para el caso comercial actual.

Desde el Javadoc:

La estrategia ansiosa es un requisito en el tiempo de ejecución del proveedor de persistencia de que los datos deben ser obtenidos ansiosos. La estrategia perezosa es una pista para el tiempo de ejecución del proveedor de persistencia de que los datos deben recuperarse perezosamente 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 pista), mientras que con las cosas ansiosas (mayo) se vuelve precipitada.

los Lazy El tipo de búsqueda se selecciona por defecto por Hibernate a menos que marque explícitamente Eager Tipo de búsqueda. Para ser más precisos y concisos, la diferencia se puede establecer como a continuación.

FetchType.LAZY = Esto no carga las relaciones a menos que las invoce 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 evitando el cálculo innecesario y reduce los requisitos de memoria.

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

Una vez dicho esto, depende de la situación Se puede usar una de estas inicialización.

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;
        }

        }

Sujeto.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();
        }
    }

    }

Verifique el método Remieve () de Main.java. Cuando tenemos sujeto, entonces su colección libros de lista, anotado con @OneToMany, se cargará perezosamente. Pero, por otro lado, la Asociación de Colección relacionada con los libros tema, anotado con @ManyToOne, carga eurgerly (por [default][1] por @ManyToOne, fetchType=EAGER). Podemos cambiar el comportamiento colocando fetchtype.age en @OneToMany Sujeto.java o fetchtype.lazy on @ManyToOne en libros. Java.

Public Enum FetchType extiende java.lang.enum Define estrategias para obtener datos de la base de datos. La estrategia ansiosa es un requisito en el tiempo de ejecución del proveedor de persistencia de que los datos deben ser obtenidos ansiosos. La estrategia perezosa es una pista para el tiempo de ejecución del proveedor de persistencia de que los datos deben recuperarse perezosamente cuando se accede por primera vez. La implementación puede obtener datos con entusiasmo para los cuales se ha especificado la estrategia perezosa. Ejemplo: @Basic (fetch = Lazy) String protegido getName () {nombre de retorno; }

Fuente

Quiero agregar esta nota a lo que dijo "Kyung Hwan Min" anteriormente.

Supongamos que está utilizando el reposo de primavera con este arquitecto simple:

Controlador <-> Servicio <-> Repositorio

Y desea devolver algunos datos al front-end, si está utilizando FetchType.LAZY, obtendrá una excepción después de devolver los datos al método del controlador ya que la sesión está cerrada en el servicio para que el servicio JSON Mapper Object No puedo obtener los datos.

Hay tres opciones comunes para resolver este problema, depende del diseño, el rendimiento y el desarrollador:

  1. El más fácil es usar FetchType.EAGER, De modo que la sesión seguirá viva en el método del controlador.
  2. Anti-paternos Soluciones, para que la sesión en vivo hasta que finalice la ejecución, es un gran problema de rendimiento en el sistema.
  3. La mejor práctica es usar FetchType.LAZY con método convertidor para transferir datos de Entity a otro objeto de datos DTO Y envíelo al controlador, por lo que no hay excepción si la sesión se cerró.

@Drop-Shadow Si estás usando Hibernate, puedes llamar Hibernate.initialize() Cuando invocas el getStudents() método:

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;
    }
    //...
}

LAZAY: Retira a las entidades infantiles perezosamente, es decir, en el momento de obtener entidad matriz, simplemente obtiene proxy (creado por cglib o cualquier otra utilidad) de las entidades infantiles y cuando accede a cualquier propiedad de la entidad infantil, en realidad la hibernación lo consigue.

ANESES: RECUBA las entidades infantiles junto con los padres.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top