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;
}
}
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;
}
//...
}
13 回答
有时你有两个实体,它们之间有关系 . 例如,您可能有一个名为University的实体和另一个名为Student的实体 .
大学实体可能有一些基本属性,如身份证,姓名,地址等,以及一个名为学生的 property :
现在,当您从数据库加载大学时,JPA会为您加载其ID,名称和地址字段 . 但是对于学生来说,你有两种选择:将它与其他字段一起加载(即急切地)或者在你调用大学的getStudents()方法时按需加载(即懒惰) .
当一所大学有很多学生时,在不需要的时候加载所有学生并不高效 . 因此,在这种情况下,您可以声明您希望学生在实际需要时加载 . 这称为延迟加载 .
基本上,
EAGER
加载集合意味着在获取父级时完全获取它们 . 因此,如果您有Course
并且它具有List<Student>
,则在获取Course
时将从数据库中提取所有学生 .另一方面,
LAZY
表示只有在您尝试访问它们时才会获取List
的内容 . 例如,通过调用course.getStudents().iterator()
. 在List
上调用任何访问方法将启动对数据库的调用以检索元素 . 这是通过在List
(或Set
)周围创建代理来实现的 . 所以对于你的懒惰集合,具体类型不是ArrayList
和HashSet
,而是PersistentSet
和PersistentList
(或PersistentBag
)我可以考虑性能和内存利用率 . 一个很大的区别是EAGER获取策略允许在没有会话的情况下使用获取的数据对象 . 为什么?
当会话连接时,当对象中的标记数据急切时,将获取所有数据 . 但是,在延迟加载策略的情况下,如果会话断开连接(在
session.close()
语句之后),则延迟加载标记的对象不会检索数据 . 所有这些都可以通过hibernate代理来完成 . 急切策略可让数据在关闭会话后仍然可用 .默认情况下,对于所有集合和映射对象,提取规则为
FetchType.LAZY
,对于其他实例,它遵循FetchType.EAGER
策略 .简而言之,
@OneToMany
和@ManyToMany
关系不会隐含地获取相关对象(集合和映射),但检索操作通过@OneToOne
和@ManyToOne
中的字段级联 .(courtesy :- objectdbcom)
据我所知,两种类型的提取都取决于您的要求 .
FetchType.LAZY
是按需的(即我们需要数据时) .FetchType.EAGER
是即时的(即在我们的要求到来之前,我们不必要地获取记录)FetchType.LAZY
和FetchType.EAGER
都用于定义default fetch plan .不幸的是,您只能覆盖LAZY抓取的默认抓取计划 . EAGER提取不太灵活,可以lead to many performance issues .
我的建议是限制使你的协会成为EAGER的冲动,因为抓取是一个查询时间的责任 . 因此,您的所有查询都应使用 fetch 指令仅检索当前业务案例所需的内容 .
来自Javadoc:
例如,渴望比懒惰更积极主动 . 懒惰只在第一次使用时发生(如果提供者接受提示),而急切的事情(可能)会预先获取 .
除非您明确标记
Eager
Fetch类型,否则Hibernate默认选择Lazy
Fetch类型 . 为了更准确和简洁,差异可以如下所述 .FetchType.LAZY
=除非您通过getter方法调用它,否则不会加载关系 .FetchType.EAGER
=这会加载所有关系 .这两种获取类型的优点和缺点 .
Lazy initialization
通过避免不必要的计算和减少内存需求来提高性能 .Eager initialization
占用更多内存,处理速度慢 .话虽如此, depends on the situation 可以使用这些初始化中的任何一个 .
Book.java
Subject.java
HibernateUtil.java
Main.java
检查Main.java的retrieve()方法 . 当我们得到Subject时,它的集合listBooks,用
@OneToMany
注释,将被懒惰地加载 . 但是,另一方面,书籍相关的收集主题协会,注释@ManyToOne
,正在加载([default][1]
为@ManyToOne
,fetchType=EAGER
) . 我们可以通过在@OneToMany
Subject.java上放置fetchType.EAGER或在Books.java中的@ManyToOne
上放置fetchType.LAZY来更改行为 .Source
@ drop-shadow如果你正在使用Hibernate,你可以在调用
getStudents()
方法时调用Hibernate.initialize()
:LAZY:它懒惰地获取子实体,即在获取父实体时它只获取子实体的代理(由cglib或任何其他实用程序创建),当您访问子实体的任何属性时,它实际上是由hibernate获取的 .
EAGER:它与父级一起获取子实体 .
为了更好地理解,请转到Jboss文档,或者您可以将
hibernate.show_sql=true
用于您的应用程序并检查hibernate发出的查询 .