Java Persistence API中的FetchType LAZY和EAGER的区别?
我是Java持久性API和Hibernate的新手。
Java Persistence API中的FetchType.LAZY
和FetchType.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不是ArrayList
和HashSet
,而是PersistentSet
和PersistentList
(或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.LAZY
和FetchType.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发出的查询。