Hibernate JPA中的Join fetch有时会导致LazyInitializationException异常

Hibernate JPA中的Join fetch有时会导致LazyInitializationException异常,hibernate,spring-mvc,ejb,jpa-2.0,lazy-initialization,Hibernate,Spring Mvc,Ejb,Jpa 2.0,Lazy Initialization,我在我的申请中遇到了这个问题。我有一个父实体艺术家,与其他实体有一对一/多蚀刻关系,我都设置为延迟获取。我使用连接查询获取这些实体。这一切似乎都很好,但有时我会遇到懒散的初始化异常。我在后端使用带有JPA的无状态EJB,在web层使用SpringMVC。方法如下: public Artist getArtistWithChildren(long id, boolean isFetchReviews, boolean isFetchRequests, boolean isFetchGigs, bo

我在我的申请中遇到了这个问题。我有一个父实体艺术家,与其他实体有一对一/多蚀刻关系,我都设置为延迟获取。我使用连接查询获取这些实体。这一切似乎都很好,但有时我会遇到懒散的初始化异常。我在后端使用带有JPA的无状态EJB,在web层使用SpringMVC。方法如下:

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);
}
public Artist getArtistWithChildren(长id、布尔值isFetchReviews、布尔值isFetchRequests、布尔值isFetchGigs、布尔值isfetchvices){
StringBuilder sql=新的StringBuilder();
append(“从a join fetch a.members中选择一个艺术家”);
如果(iFetchReviews){
append(“左连接a.rvs”);
}if(isFetchRequests){
append(“left join a.rqs”);
}if(isFetchGigs){
append(“left join a.gigs”);
}国际单项体育联合会(国际单项体育联合会){
append(“左连接a.vs”);
}
append(“其中a.id=:id”);

TypedQuery

通常,当您在集合上惰性加载并尝试在没有包含上下文的会话(方法)的情况下访问该集合时,会发生LazyInitializationException如果您可以发布错误堆栈跟踪以获得问题的准确解决方案,则会更有帮助。一般来说,当您延迟加载集合并尝试访问该集合时,如果没有包含上下文的会话,则会发生LazyInitializationExceptionxt(基本上是一种方法),您正试图在其中访问惰性集合。如果您可以发布错误堆栈跟踪以获得问题的确切解决方案,这将更有帮助。

以下是原因解释:

问题

典型(web-)应用程序中的一个常见问题是在操作的主要逻辑完成后呈现视图,因此,Hibernate会话已关闭,数据库事务已结束。如果访问JSP内会话中加载的分离对象(或任何其他视图呈现机制)时,可能会遇到未加载的集合或未初始化的代理。得到的异常是:LazyInitializationException:会话已关闭(或一条非常类似的消息)。当然,这是意料之中的,毕竟您已经结束了工作单元

一个解决方案是调用视图中的opensession模式。对于基于spring的应用程序,您可以使用
org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor
org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
,但您不能在一个项目中同时使用这两种模式

但出于某种原因,它被视为反模式:

**参考:**


以下是原因解释:

问题

典型(web-)应用程序中的一个常见问题是在操作的主要逻辑完成后呈现视图,因此,Hibernate会话已关闭,数据库事务已结束。如果访问JSP内会话中加载的分离对象(或任何其他视图呈现机制)时,可能会遇到未加载的集合或未初始化的代理。得到的异常是:LazyInitializationException:会话已关闭(或一条非常类似的消息)。当然,这是意料之中的,毕竟您已经结束了工作单元

一个解决方案是调用视图中的opensession模式。对于基于spring的应用程序,您可以使用
org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor
org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
,但您不能在一个项目中同时使用这两种模式

但出于某种原因,它被视为反模式:

**参考:**


我添加了堆栈跟踪作为链接。没有会话,就没有事务。例如,分离的实体我的不好,没有会话就有。感谢您纠正我。我可以看到以下消息:“无法初始化代理-无会话”。正如我前面提到的,这个问题是因为您试图访问延迟加载的集合,但加载集合的会话已关闭。此外,我可以从堆栈跟踪中看到,您正在使用Spring作为应用程序框架。如果是这种情况,请尝试在您要访问的方法上使用@Transactional annotatione访问延迟加载的集合。不是真的。如果我正确理解了您的问题,您将在JSP视图中传递从EJB层获得的对象,这就是访问延迟集合的时间点。如果是,我会说,尝试在早期阶段访问它(在会话上下文中绑定的方法),遍历集合,并将其设置为不同的对象(可能是DTO)注意:如果你打算使用OSIV,你有可能会面临hibernate的N+1问题,这可能会增加视图加载时间。我将堆栈跟踪添加为链接。没有会话,不能没有事务。例如,分离的实体我不好,没有会话,是的。谢谢你纠正我。我是able查看以下消息:“无法初始化代理-无会话”。正如我前面提到的,这个问题是因为您试图访问延迟加载的集合,但加载集合的会话已关闭。此外,我可以从堆栈跟踪中看到,您正在使用Spring作为应用程序框架。如果是这种情况,请尝试在您要访问的方法上使用@Transactional annotatione访问延迟加载的集合。不是真的。如果我理解
@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...