首页 文章

Java Persistence API中FetchType LAZY和EAGER之间的区别?

提问于
浏览
434

我是Java Persistence API和Hibernate的新手 .

Java Persistence API中FetchType.LAZYFetchType.EAGER有什么区别?

13 回答

  • 9

    有时你有两个实体,它们之间有关系 . 例如,您可能有一个名为University的实体和另一个名为Student的实体 .

    大学实体可能有一些基本属性,如身份证,姓名,地址等,以及一个名为学生的 property :

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

    现在,当您从数据库加载大学时,JPA会为您加载其ID,名称和地址字段 . 但是对于学生来说,你有两种选择:将它与其他字段一起加载(即急切地)或者在你调用大学的getStudents()方法时按需加载(即懒惰) .

    当一所大学有很多学生时,在不需要的时候加载所有学生并不高效 . 因此,在这种情况下,您可以声明您希望学生在实际需要时加载 . 这称为延迟加载 .

  • 0

    基本上,

    LAZY = fetch when needed
    EAGER = fetch immediately
    
  • 10

    EAGER 加载集合意味着在获取父级时完全获取它们 . 因此,如果您有 Course 并且它具有 List<Student> ,则在获取 Course 时将从数据库中提取所有学生 .

    另一方面, LAZY 表示只有在您尝试访问它们时才会获取 List 的内容 . 例如,通过调用 course.getStudents().iterator() . 在 List 上调用任何访问方法将启动对数据库的调用以检索元素 . 这是通过在 List (或 Set )周围创建代理来实现的 . 所以对于你的懒惰集合,具体类型不是 ArrayListHashSet ,而是 PersistentSetPersistentList (或 PersistentBag

  • 6

    我可以考虑性能和内存利用率 . 一个很大的区别是EAGER获取策略允许在没有会话的情况下使用获取的数据对象 . 为什么?
    当会话连接时,当对象中的标记数据急切时,将获取所有数据 . 但是,在延迟加载策略的情况下,如果会话断开连接(在 session.close() 语句之后),则延迟加载标记的对象不会检索数据 . 所有这些都可以通过hibernate代理来完成 . 急切策略可让数据在关闭会话后仍然可用 .

  • 56

    默认情况下,对于所有集合和映射对象,提取规则为 FetchType.LAZY ,对于其他实例,它遵循 FetchType.EAGER 策略 .
    简而言之, @OneToMany@ManyToMany 关系不会隐含地获取相关对象(集合和映射),但检索操作通过 @OneToOne@ManyToOne 中的字段级联 .

    (courtesy :- objectdbcom)

  • 848

    据我所知,两种类型的提取都取决于您的要求 .

    FetchType.LAZY 是按需的(即我们需要数据时) .

    FetchType.EAGER 是即时的(即在我们的要求到来之前,我们不必要地获取记录)

  • 236

    FetchType.LAZYFetchType.EAGER 都用于定义default fetch plan .

    不幸的是,您只能覆盖LAZY抓取的默认抓取计划 . EAGER提取不太灵活,可以lead to many performance issues .

    我的建议是限制使你的协会成为EAGER的冲动,因为抓取是一个查询时间的责任 . 因此,您的所有查询都应使用 fetch 指令仅检索当前业务案例所需的内容 .

  • 4

    来自Javadoc

    EAGER策略是持久性提供程序运行时的一项要求,即必须急切地获取数据 . LAZY策略是持久性提供程序运行时的提示,即数据在首次访问时应该被懒惰地获取 .

    例如,渴望比懒惰更积极主动 . 懒惰只在第一次使用时发生(如果提供者接受提示),而急切的事情(可能)会预先获取 .

  • 1

    除非您明确标记 Eager Fetch类型,否则Hibernate默认选择 Lazy Fetch类型 . 为了更准确和简洁,差异可以如下所述 .

    FetchType.LAZY =除非您通过getter方法调用它,否则不会加载关系 .

    FetchType.EAGER =这会加载所有关系 .

    这两种获取类型的优点和缺点 .

    Lazy initialization 通过避免不必要的计算和减少内存需求来提高性能 .

    Eager initialization 占用更多内存,处理速度慢 .

    话虽如此, depends on the situation 可以使用这些初始化中的任何一个 .

  • 13

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

    检查Main.java的retrieve()方法 . 当我们得到Subject时,它的集合listBooks,用 @OneToMany 注释,将被懒惰地加载 . 但是,另一方面,书籍相关的收集主题协会,注释 @ManyToOne ,正在加载( [default][1]@ManyToOnefetchType=EAGER ) . 我们可以通过在 @OneToMany Subject.java上放置fetchType.EAGER或在Books.java中的 @ManyToOne 上放置fetchType.LAZY来更改行为 .

  • 11

    public enum FetchType extends java.lang.Enum定义从数据库中获取数据的策略 . EAGER策略是持久性提供程序运行时的一项要求,必须急切地获取数据 . LAZY策略是持久性提供程序运行时的提示,即数据在首次访问时应该被懒惰地获取 . 允许实现急切地获取已指定LAZY策略提示的数据 . 示例:@Basic(fetch = LAZY)protected String getName(){return name; }

    Source

  • 0

    @ drop-shadow如果你正在使用Hibernate,你可以在调用 getStudents() 方法时调用 Hibernate.initialize()

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

    LAZY:它懒惰地获取子实体,即在获取父实体时它只获取子实体的代理(由cglib或任何其他实用程序创建),当您访问子实体的任何属性时,它实际上是由hibernate获取的 .

    EAGER:它与父级一起获取子实体 .

    为了更好地理解,请转到Jboss文档,或者您可以将 hibernate.show_sql=true 用于您的应用程序并检查hibernate发出的查询 .

相关问题