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

我是Java持久性API和Hibernate的新手。

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

有时你有两个实体,他们之间有一个关系。 例如,您可能有一个名为“大学”的实体,另一个名为“学生”的实体。

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

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

现在,当您从数据库加载大学时,JPA会为您加载其ID,名称和地址字段。 但是,对于学生来说,您有两个select:在您调用大学的getStudents()方法时,将其与其余字段(即热切地)一起加载或按需加载(即,延迟)。

当一所大学有许多学生时,在不需要的时候加载所有的学生是没有效率的。 因此,在这种情况下,您可以声明您希望在实际需要时加载学生。 这被称为延迟加载。

基本上,

 LAZY = fetch when needed EAGER = fetch immediately 

EAGER加载收集意味着它们在获取父母时被完全提取。 所以如果你有Course而且它有List<Student> ,所有的学生都是在Course被提取的时候从数据库中提取的。

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

我可能会考虑性能和内存利用率。 EAGER获取策略允许使用获取的数据对象,而不需要会话。 为什么?
会话连接时,在对象中标记数据时,所有数据都会被提取。 但是,在延迟加载策略的情况下,如果会话断开连接(在session.close()语句之后session.close() ,则延迟加载标记对象不检索数据。 所有这一切都可以通过hibernate代理。 Eager策略让数据在closures会话后仍然可用。

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

(礼貌: – objectdbcom)

据我所知,这两种types的取指取决于您的要求。

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

FetchType.EAGER是立即的(即在我们的要求来临之前,我们不必要地提取logging)

从Javadoc :

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

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

FetchType.LAZYFetchType.EAGER都用于定义默认的抓取计划 。

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

我的build议是抑制使您的协会EAGER的冲动,因为提取是一个查询时间的责任。 因此,您的所有查询都应使用fetch指令来检索当前业务案例的必要条件。

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()方法。 当我们得到主题,那么它的集合listBooks@OneToMany注释将被加载懒惰。 但是,另一方面,Books关联的集合主题 ,用@ManyToOne注释,加载(由@ManyToOne [default][1]fetchType=EAGER )。 我们可以通过在@OneToMany Subject.java上放置fetchType.EAGER或在@ManyToOne @ManyToOne上放置fetchType.LAZY来改变行为。

Lazy Fetchtypes默认由Hibernateselect,除非您明确标记了Eager Fetchtypes。 为了更加准确和简洁,可以将差异表述如下。

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

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

这两种获取types的优缺点。

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

Eager initialization需要更多的内存消耗,处理速度很慢。

话虽如此, 视情况而定 ,这些初始化中的任何一个都可以使用。

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

资源

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

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

EAGER:它与父母一起获取子实体。

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