我在我的应用程序中遇到了JPA这个问题。我有一个父实体艺术家与其他实体的一对一/多个蚀刻关系,我已经设置为懒惰获取。我使用连接查询获取这些实体。这一切似乎工作正常,但有时我得到一个LazyInitializationException。我在后端使用无状态EJB和在Web层使用Spring MVC。这是方法:
public Artist getArtistWithChildren(long id, boolean isFetchReviews, boolean isFetchRequests, boolean isFetchGigs, boolean isFetchVenues) {
StringBuilder sql = new StringBuilder();
sql.append("select a from Artist a join fetch a.members mrs");
if(isFetchReviews) {
sql.append(" left join a.reviews rvs");
} if(isFetchRequests) {
sql.append(" left join a.requests rqs");
} if(isFetchGigs) {
sql.append(" left join a.gigs gs");
} if(isFetchVenues) {
sql.append(" left join a.venues vs");
}
sql.append(" where a.id=:id");
TypedQuery<Artist> query = em.createQuery(sql.toString(), Artist.class);
query.setParameter("id", id);
query.setMaxResults(1);
List<Artist> resultList = query.getResultList();
return resultList.get(0);
}
这是实体类Artist
@Entity
@Table(name="ARTIST")
public class Artist extends DescribingEntity {
private static final long serialVersionUID = -7264327449601568983L;
@ManyToMany(mappedBy="artists", targetEntity=Member.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH})
private List<Member> members;
@OneToMany(mappedBy="artist", targetEntity=VenueReview.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<VenueReview> reviews;
@OneToMany(mappedBy="artist", targetEntity=Gig.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<Gig> gigs;
@OneToMany(mappedBy="artist", targetEntity=GigRequest.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<GigRequest> requests;
@ManyToMany(cascade={MERGE, REFRESH}, fetch=FetchType.LAZY)
@JoinTable(name="VENUE_ARTIST_REL",
joinColumns=@JoinColumn(name="ARTIST_ID", referencedColumnName="ARTIST_ID"),
inverseJoinColumns=@JoinColumn(name="VENUE_ID", referencedColumnName="VENUE_ID"))
private List<Venue> venues;
getters and setters...
然后我进入调试模式以找出出错的地方,因为我正在逐步执行该方法,它不会返回任何错误,也不会抛出任何异常。可能是收集过早返回,以便数据库中的所有数据都没有时间正确填充?说到JPA,我是新手,所以请让我知道我做错了什么。这是一个例子。我在这里使用左连接,因为我没有得到结果,但我需要一个实例化的集合。
我使用Arquillian测试了相同的东西并且没有错误,我也有类似的方法用于场景相同的其他实体,简单地运行它会导致错误,而逐步调试则不会。
在子集合上使用Hibernate.initialize(Object o)
工作正常,但据我所知,这不是一件好事,因为我必须为每个孩子进行数据库查询(如果我错了,请纠正我)。 / p>
我在堆栈跟踪
中添加了一个pastebin链接答案 0 :(得分:1)
一般情况下,LazyInitializationException发生在你对一个集合进行延迟加载并尝试访问该集合时,没有一个Session包含你试图访问lazy集合的上下文(本质上是方法)。如果您可以发布错误堆栈跟踪以获得问题的精确解决方案,那将会更有帮助
答案 1 :(得分:1)
以下是原因解释:
问题
典型(web)应用程序中的一个常见问题是在操作的主要逻辑完成之后呈现视图,因此,Hibernate会话已经关闭并且数据库事务已经结束。如果访问已在JSP(或任何其他视图呈现机制)内的Session中加载的分离对象,则可能会遇到未加载的集合或未初始化的代理。您得到的异常是:LazyInitializationException:会话已关闭(或非常类似的消息)。当然,毕竟你已经结束了你的工作单元,这是可以预期的。
解决方案是调用在视图中打开会话模式。使用基于Spring的应用程序,您可以使用org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor
或org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
,但您不能在一个项目中同时使用它们。
但是对于某些原因,它被视为反模式:
**参考:**