LazyInitializationException: 延迟初始化角色集合失败 无法初始化代理 - 没有会话

Posted

技术标签:

【中文标题】LazyInitializationException: 延迟初始化角色集合失败 无法初始化代理 - 没有会话【英文标题】:LazyInitializationException: failed to lazily initialize a collection of role could not initialize proxy - no Session 【发布时间】:2015-04-01 21:51:39 【问题描述】:

这在 SO 中被多次询问。但是他们没有解决我的问题,所以再次发布。

尝试访问我的应用程序时出现以下异常

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.wpt.models.Item.itemCategory, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
    at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294)
    at org.apache.taglibs.standard.tag.common.core.ForEachSupport.toForEachIterator(ForEachSupport.java:348)
    at org.apache.taglibs.standard.tag.common.core.ForEachSupport.supportedTypeForEachIterator(ForEachSupport.java:224)
    at org.apache.taglibs.standard.tag.common.core.ForEachSupport.prepare(ForEachSupport.java:155)
    at javax.servlet.jsp.jstl.core.LoopTagSupport.doStartTag(LoopTagSupport.java:256)

web.xml

<filter>
        <filter-name>HibernateFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>sessionFactoryBeanName</param-name>
            <param-value>hibernate4AnnotatedSessionFactory</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>HibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

<servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

弹簧配置:

<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"
    p:sessionFactory-ref="hibernate4AnnotatedSessionFactory">
</bean>

Item.java

@Entity
@Table(name="item")
public class Item 
    @OneToMany(mappedBy="item", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    private List<ItemCategory> itemCategory = new ArrayList<ItemCategory>();

ItemServiceImpl.java

@Override
    @Transactional(readOnly=true)
    public List<Item> getItemsByCategory(int categoryId) 
        return itemDAO.getItemsByCategory(categoryId);
    

在所有博客中,建议要么使用EAGER fetch,要么使用OpenSessionInViewFilter 支持@Transactional

如果我使用EAGER fetch,它会起作用。但不是以另一种方式工作。我已经使用@Transactional 注释实现了所有服务方法。我在这里犯了什么错误?有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

使用下面的过滤器代替 HibernateFilter

<filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

希望对你有所帮助。

【讨论】:

我不认为这是问题所在。它只是用户定义的过滤器名称。它可以是任何东西。这个问题已经解决了,我已经给出了答案。 这是由于错过了将 contextConfigLocation 初始化为 DispatcherServlet。一旦我初始化它就解决了。【参考方案2】:

首先,您已经意识到如果您急切地提取会发生什么。这意味着当您请求项目时,对数据库的查询总是会带来 itemCategory。也许这不是您所期望的行为。

二、lazyInitialization异常是因为你在关闭会话后试图访问对象itemCategory。我想当您从方法“getItemsByCategorymethod”收到列表时会话已关闭。

我通常解决这种情况的方法(不是急切获取)有两种方法:

在关闭会话之前选择 itemCategory。无论你在哪里调用来执行查询,你都应该可以说List listItemCategroy = item.getItemCategory()

将 fetch.JOIN 添加到表 itemCategory 中,它将带来 ItemCategory。

如果你想避免这个错误,你可以在你的代码中添加这个:

if (Hibernate.isInitilized())
    ....

如果对象已初始化则返回 true,否则返回 false。

【讨论】:

是的,我注意到了。但是 fatch.JOIN 和 FetchType.EAGER 不一样?对不起,我在这方面有点困惑。你能给我一个详细解释的参考吗? (我浏览了一些链接,但细节还不够) 如果您在实体中指明 FetchType.EAGER,它将与您从数据库中检索的所有项目对象有关。但是,如果您的关系是惰性的并在条件中指示 fetch.JOIN,那么您只是说该查询使关系急切。认为您在请求项目时并不总是需要 itemCategory。假设您只需要 item_pk 作为列表,您是否还需要检索 itemCategory 对象?【参考方案3】:

contextConfigLocation 用于指示 xml 文件(例如 Spring、spring-security)所在的位置。

懒惰的问题对我来说对 Spring 配置没有任何意义。

你能详细解释一下吗?

【讨论】:

是的,我也明白这一点。我认为当我们使用 OpenSessionInViewFilter 时,DispatcherServlet 能够识别 Spring 配置文件中的 sessionFactoryBean,只是我们通过它的 init-param 对其进行初始化。对此做一些分析。一旦找到它发生这种情况的正当原因,就会发布它。【参考方案4】:

好的,经过一番努力,我终于想出了解决这个问题的办法。

在我将contextConfigLocation 添加到DispatcherServlet's &lt;init-param&gt; 后问题得到解决。更改后,我的DispatcherServlet 配置如下所示。

<servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

参考:This post

【讨论】:

以上是关于LazyInitializationException: 延迟初始化角色集合失败 无法初始化代理 - 没有会话的主要内容,如果未能解决你的问题,请参考以下文章