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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2990799/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 15:19:41  来源:igfitidea点击:

Difference between FetchType LAZY and EAGER in Java Persistence API?

javahibernatejpaormjava-persistence-api

提问by leon

I am a newbie to Java Persistence API and Hibernate.

我是 Java Persistence API 和 Hibernate 的新手。

What is the difference between FetchType.LAZYand FetchType.EAGERin Java Persistence API?

Java Persistence APIFetchType.LAZYFetchType.EAGERJava Persistence API之间有什么区别?

采纳答案by Behrang Saeedzadeh

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

有时,您有两个实体,并且它们之间存在关系。例如,您可能有一个实体称为University另一个实体,Student并且大学可能有许多学生:

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:

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

A university has many students

一所大学有很多学生

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:

现在,当您从数据库加载大学时,JPA 会为您加载其 id、名称和地址字段。但是对于如何加载学生,您有两种选择:

  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.
  1. 将它与其他字段一起加载(即热切地),或
  2. 当您调用大学的getStudents()方法时按需(即懒惰)加载它。

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 studentsis explicitly marked to be loaded eagerly:

这是一个示例,其中students明确标记为急切加载:

@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 studentsis explicitly marked to be loaded lazily:

这是一个students明确标记为延迟加载的示例:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.
}

回答by unbeli

Basically,

基本上,

LAZY = fetch when needed
EAGER = fetch immediately

回答by T.J. Crowder

From the Javadoc:

Javadoc

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed.

EAGER 策略是对持久性提供程序运行时的一项要求,即必须急切地获取数据。LAZY 策略是对持久性提供程序运行时的一个提示,即在第一次访问数据时应该延迟获取数据。

E.g., eager is more proactive than lazy. Lazy only happens on first use (if the provider takes the hint), whereas with eager things (may) get pre-fetched.

例如,渴望比懒惰更主动。懒惰只在第一次使用时发生(如果提供者接受提示),而急切的东西(可能)会被预取。

回答by Bozho

EAGERloading of collections means that they are fetched fully at the time their parent is fetched. So if you have Courseand it has List<Student>, all the students are fetched from the databaseat the time the Courseis fetched.

EAGER加载集合意味着在获取它们的父项时完全获取它们。所以,如果你有Course,它有 List<Student>,所有的学生都获取从数据库在当时Course被取出。

LAZYon the other hand means that the contents of the Listare fetched only when you try to access them. For example, by calling course.getStudents().iterator(). Calling any access method on the Listwill 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 ArrayListand HashSet, but PersistentSetand PersistentList(or PersistentBag)

LAZY另一方面意味着List只有当您尝试访问它们时才会获取的内容。例如,通过调用course.getStudents().iterator(). 调用 上的任何访问方法List将启动对数据库的调用以检索元素。这是通过围绕List(或Set)创建代理来实现的。因此,对于您的惰性集合,具体类型不是ArrayListand HashSet,而是PersistentSetand PersistentList(or PersistentBag)

回答by Kyung Hwan Min

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 fetch 策略允许在没有会话的情况下使用已获取的数据对象。为什么?
当会话连接时在对象中预先标记数据时获取所有数据。但是,在延迟加载策略的情况下,如果会话断开(在session.close()语句之后),延迟加载标记的对象不会检索数据。所有这些都可以通过休眠代理完成。Eager 策略让数据在关闭会话后仍然可用。

回答by babai

By default, for all collection and map objects the fetching rule is FetchType.LAZYand for other instances it follows the FetchType.EAGERpolicy.
In brief, @OneToManyand @ManyToManyrelations does not fetch the related objects (collection and map) implicictly but the retrieval operation is cascaded through the field in @OneToOneand @ManyToOneones.

默认情况下,对于所有集合和映射对象,获取规则是FetchType.LAZY,对于其他实例,它遵循FetchType.EAGER策略。
简言之,@OneToMany@ManyToMany关系不implicictly获取相关对象(采集和地图),但检索操作通过现场级联@OneToOne@ManyToOne的。

(courtesy :- objectdbcom)

(礼貌:- objectdbcom)

回答by Jules Martel

@drop-shadow if you're using Hibernate, you can call Hibernate.initialize()when you invoke the getStudents()method:

@drop-shadow 如果您使用的是 Hibernate,则可以Hibernate.initialize()在调用该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;
    }
    //...
}

回答by JDGuide

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

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

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

FetchType.LAZY按需(即当我们需要数据时)。

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

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

回答by Vlad Mihalcea

Both FetchType.LAZYand FetchType.EAGERare used to define the default fetch plan.

双方FetchType.LAZYFetchType.EAGER用来定义默认提取计划

Unfortunately, you can only override the default fetch plan for LAZY fetching. EAGER fetching is less flexible and can lead to many performance issues.

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

My advice is to restrain the urge of making your associations EAGER because fetching is a query-time responsibility. So all your queries should use the fetchdirective to only retrieve what's necessary for the current business case.

我的建议是抑制让你的关联变得 EAGER 的冲动,因为获取是查询时的责任。因此,您的所有查询都应使用fetch指令来仅检索当前业务案例所需的内容。

回答by Deepak

Book.java

书.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

主题.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

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 @OneToManySubject.java or fetchType.LAZY on @ManyToOnein Books.java.

检查 Main.java 的retrieve() 方法。当我们获得 Subject 时,它的集合listBooks@OneToMany将被延迟加载,注释为。但是,另一方面,书籍相关的收藏主题关联,用 注释@ManyToOne,急切地加载(通过[default][1]for @ManyToOnefetchType=EAGER)。我们可以通过在@OneToManySubject.java 上放置 fetchType.EAGER或@ManyToOne在 Books.java 中放置 fetchType.LAZY 来改变行为。