Difference between FetchType LAZY and EAGER in Java Persistence API?

后端 未结 15 992
鱼传尺愫
鱼传尺愫 2020-11-22 08:08

I am a newbie to Java Persistence API and Hibernate.

What is the difference between FetchType.LAZY and FetchType.EAGER in Java Persistence API?

相关标签:
15条回答
  • 2020-11-22 08:49

    By default, for all collection and map objects the fetching rule is FetchType.LAZY and for other instances it follows the FetchType.EAGER policy.
    In brief, @OneToMany and @ManyToMany relations does not fetch the related objects (collection and map) implicictly but the retrieval operation is cascaded through the field in @OneToOne and @ManyToOne ones.

    (courtesy :- objectdbcom)

    0 讨论(0)
  • 2020-11-22 08:50

    As per my knowledge both type of fetch depends your requirement.

    FetchType.LAZY is on demand (i.e. when we required the data).

    FetchType.EAGER is immediate (i.e. before our requirement comes we are unnecessarily fetching the record)

    0 讨论(0)
  • 2020-11-22 08:51

    EAGER loading of collections means that they are fetched fully at the time their parent is fetched. So if you have Course and it has List<Student>, all the students are fetched from the database at the time the Course is fetched.

    LAZY on the other hand means that the contents of the List are fetched only when you try to access them. For example, by calling course.getStudents().iterator(). Calling any access method on the List will initiate a call to the database to retrieve the elements. This is implemented by creating a Proxy around the List (or Set). So for your lazy collections, the concrete types are not ArrayList and HashSet, but PersistentSet and PersistentList (or PersistentBag)

    0 讨论(0)
  • 2020-11-22 08:58

    Sometimes you have two entities and there's a relationship between them. For example, you might have an entity called University and another entity called Student and a University might have many Students:

    The University entity might have some basic properties such as id, name, address, etc. as well as a collection property called students that returns the list of students for a given university:

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

    Now when you load a University from the database, JPA loads its id, name, and address fields for you. But you have two options for how students should be loaded:

    1. To load it together with the rest of the fields (i.e. eagerly), or
    2. To load it on-demand (i.e. lazily) when you call the university's getStudents() method.

    When a university has many students it is not efficient to load all of its students together with it, especially when they are not needed and in suchlike cases you can declare that you want students to be loaded when they are actually needed. This is called lazy loading.

    Here's an example, where students is explicitly marked to be loaded eagerly:

    @Entity
    public class University {
    
        @Id
        private String id;
    
        private String name;
    
        private String address;
    
        @OneToMany(fetch = FetchType.EAGER)
        private List<Student> students;
    
        // etc.    
    }
    

    And here's an example where students is explicitly marked to be loaded lazily:

    @Entity
    public class University {
    
        @Id
        private String id;
    
        private String name;
    
        private String address;
    
        @OneToMany(fetch = FetchType.LAZY)
        private List<Student> students;
    
        // etc.
    }
    
    0 讨论(0)
  • 2020-11-22 09:00

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

    Check the retrieve() method of Main.java. When we get Subject, then its collection listBooks, annotated with @OneToMany, will be loaded lazily. But, on the other hand, Books related association of collection subject, annotated with @ManyToOne, loads eargerly (by [default][1] for @ManyToOne, fetchType=EAGER). We can change the behaviour by placing fetchType.EAGER on @OneToMany Subject.java or fetchType.LAZY on @ManyToOne in Books.java.

    0 讨论(0)
  • 2020-11-22 09:01

    Basically,

    LAZY = fetch when needed
    EAGER = fetch immediately
    
    0 讨论(0)
提交回复
热议问题