我有这两个实体
@Entity
@Table(name = "CallSession")
public class CallSession implements Serializable {
private long id;
private List<CallParticipant> members;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@OneToMany(mappedBy = "callSession", fetch = FetchType.LAZY)
public List<CallParticipant> getMembers() {
return members;
}
public void setMembers(List<CallParticipant> members) {
this.members = members;
}
}
@Entity
@Table(name = "CallParticipant")
public class CallParticipant implements Serializable {
private long id;
private CallSession callSession;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@ManyToOne
public CallSession getCallSession() {
return callSession;
}
public void setCallSession(CallSession callSession) {
this.callSession = callSession;
}
}
但是当我调用CallSession.getMembers()
方法时,我会得到以下异常:
无法计算引发“Org.Hibernate.LazyInitializationException”异常的表达式方法。
我搞不懂为什么会出现这个错误? 为什么会出现这个错误,如何修复?
您已经定义了字段members
自己,通过在getter上使用fetch=fetchType.lazy
来懒惰地获取字段。 事实上,您甚至不必那样做,因为在Hibernate中,每个X对多默认情况下都是懒惰的。
要解决这个问题,您必须使用fetch=fetchType.eager
使其成为急切状态,或者更好的方法是编写一个查询,例如在jpql中指定获取策略,如下所示:
@Query("select c from CallSession c left join fetch c.members")
我要从假设你想要你的收藏是懒惰加载开始。
Hibernate的会话可以在很多上下文中关闭,一旦关闭会话,它将无法获取任何懒惰加载的集合。
一般来说,Hibernate非常擅长在web应用上下文中的HTTP线程的生命周期中保持会话打开(spring的“open session in View”)。 会话可能关闭的原因包括对象从一个线程切换到另一个线程,或者对象被缓存,然后被另一个线程访问。
但如果代码在作业或非Web应用程序上下文中运行,则可能会更困难。
1.创建一个repository方法来显式获取集合
使用@query
和join fetch
,添加一个repository方法,该方法显式地渴望加载集合。
2.获取对象后对集合调用.toString()。
这是一个肮脏的黑客,我以前见过很多人在现实世界中使用过。 基本上,在缓存对象或将其移交给执行器或其他线程将访问它的地方之前,对集合调用。toString()来加载它。 通常会留下评论解释原因。
3.将@Transactional添加到既获取数据又访问集合的方法中
除了保持会话活动(例如,数据库操作同时成功和失败)之外,这还有许多其他含义,但是可以快速修复会话活动,例如在作业方法中。
希望这能帮上忙。