java 如何避免 Hibernate 中的 LazyInitializationException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10181584/
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
How to avoid LazyInitializationException in Hibernate?
提问by J Ellis
I am using Hibernate as the ORM for a database that has a number of foreign key relationships. The problem is that sometimes I want to fetch these related datasets and sometimes I do not, so on these collections I have set "fetch" to "lazy". Unfortunately, every time I try to serialize these objects Hibernate will throw a LazyInitializationException, because the session is closed. Using an OpenSessionInView filter simply causes Hibernate to populate these collections anyway, thus defeating the whole purpose of having a lazy collection in the first place.
我使用 Hibernate 作为具有多个外键关系的数据库的 ORM。问题是有时我想获取这些相关的数据集,有时我不想,所以在这些集合中我将“获取”设置为“懒惰”。不幸的是,每次我尝试序列化这些对象时,Hibernate 都会抛出一个 LazyInitializationException,因为会话已关闭。无论如何,使用 OpenSessionInView 过滤器只会导致 Hibernate 填充这些集合,从而首先破坏了拥有惰性集合的整个目的。
Is there a simple way to serialize or otherwise extract the data populated in the POJO without triggering the LIE, and without having to populate all of the lazy collections?
是否有一种简单的方法可以在不触发 LIE 的情况下序列化或以其他方式提取填充在 POJO 中的数据,并且不必填充所有惰性集合?
EDIT: Here is some example code I am trying to get working, dealing with two tables, "Departments" and "Employees," which is the child in a one-to-many relationship with Departments. I want to be able to view the Departments listed in the database, without having to load all of the Employees that belong to said Departments:
编辑:这是我正在尝试使用的一些示例代码,处理两个表,“部门”和“员工”,这是与部门一对多关系的孩子。我希望能够查看数据库中列出的部门,而不必加载属于所述部门的所有员工:
Departments:
部门:
package com.test.model;
// Generated Apr 7, 2012 7:10:28 PM by Hibernate Tools 3.4.0.CR1
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* Departments generated by hbm2java
*/
@Entity
@Table(name="Departments"
,catalog="test"
)
public class Departments implements java.io.Serializable {
private Integer id;
private String name;
private Set<Employees> employeeses = new HashSet(0);
public Departments() {
}
public Departments(String name) {
this.name = name;
}
public Departments(String name, Set employeeses) {
this.name = name;
this.employeeses = employeeses;
}
@Id @GeneratedValue(strategy=IDENTITY)
@Column(name="Id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="Name", nullable=false)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch=FetchType.LAZY, mappedBy="departments")
public Set<Employees> getEmployeeses() {
return this.employeeses;
}
public void setEmployeeses(Set employeeses) {
this.employeeses = employeeses;
}
}
Employees:
雇员:
package com.test.model;
// Generated Apr 7, 2012 7:10:28 PM by Hibernate Tools 3.4.0.CR1
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* Employees generated by hbm2java
*/
@Entity
@Table(name="Employees"
,catalog="test"
)
public class Employees implements java.io.Serializable {
private Integer id;
private Departments departments;
private String firstName;
private String lastName;
public Employees() {
}
public Employees(Departments departments, String firstName, String lastName) {
this.departments = departments;
this.firstName = firstName;
this.lastName = lastName;
}
@Id @GeneratedValue(strategy=IDENTITY)
@Column(name="Id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="DepartmentsId", nullable=false)
public Departments getDepartments() {
return this.departments;
}
public void setDepartments(Departments departments) {
this.departments = departments;
}
@Column(name="FirstName", nullable=false)
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name="LastName", nullable=false)
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
My action class (which gets serialized by the Struts2 XSLT result):
我的操作类(由 Struts2 XSLT 结果序列化):
package com.test.view;
import java.util.List;
import java.util.Iterator;
import com.opensymphony.xwork2.ActionSupport;
import com.test.controller.DepartmentsManager;
import com.test.model.Departments;
import com.test.util.HibernateUtil;
public class DepartmentsAction extends ActionSupport {
private DepartmentsManager departmentsManager;
private List<Departments> departmentsList;
public DepartmentsAction() {
this.departmentsManager = new DepartmentsManager();
}
public String list() {
this.departmentsList = departmentsManager.list();
System.out.println("Execute called");
HibernateUtil.createDTO(departmentsList);
return SUCCESS;
}
public List<Departments> getDepartmentsList() {
return departmentsList;
}
public void setDepartmentsList(List<Departments> departmentsList) {
this.departmentsList = departmentsList;
}
}
My Manager class (which the Action class calls to populate the list of Departments):
我的 Manager 类(Action 类调用它来填充部门列表):
package com.test.controller;
import java.util.List;
import java.util.Iterator;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import com.test.model.Departments;
import com.test.util.HibernateUtil;
public class DepartmentsManager {
public List<Departments> list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List<Departments> set = null;
try {
Query q = session.createQuery("FROM Departments");
/*Query q = session.createQuery("FROM Departments d JOIN FETCH d.employeeses e");*/
q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
set = (List<Departments>) q.list();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.getTransaction().commit();
return set;
}
}
采纳答案by Eugene Retunsky
Lazy collections work only within the scope of the transaction (where the owning entity was retrieved from a DB). In other words, you should not pass a Hibernate entity with non-loaded lazy sub-entities or collections outside the transaction scope.
惰性集合仅在事务范围内工作(从数据库中检索拥有的实体)。换句话说,您不应在事务范围之外传递带有未加载的惰性子实体或集合的 Hibernate 实体。
You need either to build another entity or use lazy="false" if you want to pass an entity to JSP, or serialization code or anything else.
如果要将实体传递给 JSP、序列化代码或其他任何内容,则需要构建另一个实体或使用 lazy="false"。
回答by Mik378
Two simple ways to manage lazy loading within view :
在视图中管理延迟加载的两种简单方法:
Using a Transaction view (consisting in wrapping view calls into JTA transaction (application-managed for instance)
Using an extented persistence context in your bean and flushing it explicitely when you've done with it, that means as soon as you were able to load your lazy objects.
使用事务视图(包括将视图调用包装到 JTA 事务中(例如应用程序管理)
在您的 bean 中使用扩展持久性上下文并在您完成后明确地刷新它,这意味着一旦您能够加载您的惰性对象。
For more information, check this post and the answer that belongs to it:
有关更多信息,请查看此帖子和属于它的答案:
JPA lazy loading Collections in JSF view - better way than using Filters?