FetchType的区别是什么。LAZY和FetchType。Java持久性API中的EAGER ?


当前回答

有一个小小的评论: 如果你使用惰性类型,如果你关闭会话,你以后将不能从数据库中获取数据(参见下面的输出)。

但是对于Eager类型,你在获取Instructor的同时获取数据,所以在session.close()之后,你将能够使用/显示这些课程列表数据。

  @OneToMany(//fetch = FetchType.EAGER, 
        fetch = FetchType.LAZY,  
           mappedBy = "instructor",        
           cascade = {CascadeType.DETACH, CascadeType.MERGE,
                CascadeType.PERSIST, CascadeType.REFRESH})
private List<Course> courseList; 

我建议在调试模式下尝试这两种方法。在这种情况下,我使用惰性类型,你可以看到。

 try {
        //start the transaction
        session.beginTransaction();

        //Get instructor from database
        int instructorId = 7;

        Instructor tempInstructor = session.get(Instructor.class,instructorId);

        System.out.println("Instructor: "+tempInstructor);


        //commit transaction
        session.getTransaction().commit();

       //close session
       session.close();

       //since courselist is lazy loaded... this should fail
       //so in here we are not able to fetch courselist data
       //get courses
        System.out.println("Courses "+tempInstructor.getCourseList() );


        System.out.println("Done!");

    } finally {
        session.close();
        factory.close();
    }
}

输出异常:

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.exercise.hibernate.entity.Instructor.courseList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:621)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408)
at com.exercise.hibernate.main.EagerLazyLoading.main(EagerLazyLoading.java:56)

其他回答

有时你有两个实体它们之间有关系。例如,你可能有一个实体叫University,另一个实体叫Student,一个University可能有很多Student:

University实体可能有一些基本属性,如id、名称、地址等,以及一个名为students的集合属性,它返回给定大学的学生列表:

public class University {
   private String id;
   private String name;
   private String address;
   private List<Student> students;

   // setters and getters
}

现在,当您从数据库加载University时,JPA将为您加载它的id、名称和地址字段。但是你有两种选择:

将它与其他字段一起加载(即急切地加载),或者 在调用大学的getStudents()方法时按需加载它(即惰性加载)。

当一所大学有很多学生时,加载所有的学生并不是有效的,特别是当他们不需要的时候,在这种情况下,你可以声明你想要在实际需要学生的时候加载他们。这被称为惰性加载。

下面是一个例子,学生被明确地标记为急切加载:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.    
}

这里有一个例子,学生被明确地标记为惰性加载:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.
}

I may consider performance and memory utilization. One big difference is that EAGER fetch strategy allows to use fetched data object without session. Why? All data is fetched when eager marked data in the object when session is connected. However, in case of lazy loading strategy, lazy loading marked object does not retrieve data if session is disconnected (after session.close() statement). All that can be made by hibernate proxy. Eager strategy lets data to be still available after closing session.

有一个小小的评论: 如果你使用惰性类型,如果你关闭会话,你以后将不能从数据库中获取数据(参见下面的输出)。

但是对于Eager类型,你在获取Instructor的同时获取数据,所以在session.close()之后,你将能够使用/显示这些课程列表数据。

  @OneToMany(//fetch = FetchType.EAGER, 
        fetch = FetchType.LAZY,  
           mappedBy = "instructor",        
           cascade = {CascadeType.DETACH, CascadeType.MERGE,
                CascadeType.PERSIST, CascadeType.REFRESH})
private List<Course> courseList; 

我建议在调试模式下尝试这两种方法。在这种情况下,我使用惰性类型,你可以看到。

 try {
        //start the transaction
        session.beginTransaction();

        //Get instructor from database
        int instructorId = 7;

        Instructor tempInstructor = session.get(Instructor.class,instructorId);

        System.out.println("Instructor: "+tempInstructor);


        //commit transaction
        session.getTransaction().commit();

       //close session
       session.close();

       //since courselist is lazy loaded... this should fail
       //so in here we are not able to fetch courselist data
       //get courses
        System.out.println("Courses "+tempInstructor.getCourseList() );


        System.out.println("Done!");

    } finally {
        session.close();
        factory.close();
    }
}

输出异常:

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.exercise.hibernate.entity.Instructor.courseList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:621)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408)
at com.exercise.hibernate.main.EagerLazyLoading.main(EagerLazyLoading.java:56)

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

(提供:- objectdbcom)

FetchType。LAZY和FetchType。EAGER用于定义默认的读取计划。

不幸的是,您只能覆盖LAZY抓取的默认抓取计划。EAGER抓取不太灵活,可能导致许多性能问题。

我的建议是克制将关联设置为EAGER的冲动,因为取回是查询时的责任。因此,您的所有查询都应该使用fetch指令来只检索当前业务用例所需的内容。