Java 休眠惰性初始化异常

Java 休眠惰性初始化异常,java,hibernate,Java,Hibernate,我正在尝试使用SpringMVC和hibenate创建一个应用程序。近两天来,我一直看到延迟初始化角色集合的异常失败:如果我急切地加载集合,应用程序运行良好。但我不想这样 我尝试在web.xml中实现OpenSessionInViewFilter,但错误仍然存在。我试图扩展OpenSessionInViewFilter并使用我自己的过滤器,即使现在这个问题仍然没有解决。这是我实现的过滤器 public class HibernateFilter extends OpenSessionInView

我正在尝试使用SpringMVC和hibenate创建一个应用程序。近两天来,我一直看到延迟初始化角色集合的异常失败:如果我急切地加载集合,应用程序运行良好。但我不想这样

我尝试在web.xml中实现OpenSessionInViewFilter,但错误仍然存在。我试图扩展OpenSessionInViewFilter并使用我自己的过滤器,即使现在这个问题仍然没有解决。这是我实现的过滤器

public class HibernateFilter extends OpenSessionInViewFilter {

    @Override
    protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {

  Session session = super.getSession(sessionFactory);
  session.setFlushMode(FlushMode.AUTO);
  return session;
    }

    @Override
    protected void closeSession(Session session, SessionFactory sessionFactory) {
        try {
            if (session != null && session.isOpen() && session.isConnected()) {
                try {
                    session.flush();
                } catch (HibernateException e) {
                    throw new CleanupFailureDataAccessException("Failed to flush session before close: " + e.getMessage(), e);
                } catch (Exception e) {
                }
            }
        } finally {
            super.closeSession(session, sessionFactory);
        }
    }
}
我以调试模式运行应用程序。我发现会话不为null,closeSession只有在通过控制器代码后才会被调用。但是,如果在会话打开时尝试在控制器中提取集合,它仍然会失败:下面是我的web.xml:

提出的例外情况:

StandardWrapperValve[try-blog]: PWC1406: Servlet.service() for servlet try-blog threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ValueObjects.User.blogs, no session or session was closed
        at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
        at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
        at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
        at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
        at org.hibernate.collection.PersistentSet.toArray(PersistentSet.java:194)
        at java.util.ArrayList.<init>(ArrayList.java:131)
        at Controllers.UserController.show(UserController.java:52)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
        at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:427)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:333)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
        at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:313)
        at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
        at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
        at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
        at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)

很可能您使用的是分离的对象,即在与OpenSessionInViewFilter创建的会话不同的会话中加载的对象。当您在会话中存储对象并从后续请求访问它们时,可能会发生这种情况。这可能吗

编辑:

我不鼓励将用户对象保留在会话中。相反,每次需要时,只保留id并从DB获取用户对象。因此,您应该使用这样的方法,而不是当前的方法

User getUserFromSession(HttpSession session) {
  Integer userId = (Integer) session.getAttribute("currentUser"); 
  return userId != null ? getObjectById(User.class, userId) : null;
}
请注意,按id获取对象的速度非常快,特别是如果您已将Hibernate的二级缓存配置为存储用户对象,那么就不要考虑任何性能问题。不过,它的主要优点是,您不必再处理分离的对象。分离的物体是邪恶的,没有人喜欢它们


正如@skaffman所提到的,返回默认的OpenSessionInViewFilter,因为您的实现显然无法解决您的问题。

很可能您使用的是分离的对象,即加载在与OpenSessionInViewFilter创建的会话不同的会话中的对象。当您在会话中存储对象并从后续请求访问它们时,可能会发生这种情况。这可能吗

编辑:

我不鼓励将用户对象保留在会话中。相反,每次需要时,只保留id并从DB获取用户对象。因此,您应该使用这样的方法,而不是当前的方法

User getUserFromSession(HttpSession session) {
  Integer userId = (Integer) session.getAttribute("currentUser"); 
  return userId != null ? getObjectById(User.class, userId) : null;
}
请注意,按id获取对象的速度非常快,特别是如果您已将Hibernate的二级缓存配置为存储用户对象,那么就不要考虑任何性能问题。不过,它的主要优点是,您不必再处理分离的对象。分离的物体是邪恶的,没有人喜欢它们


正如@skaffman所提到的,返回默认的OpenSessionInViewFilter,因为您的实现显然无法解决您的问题。

如果您的代码在控制器中失败,那么该过滤器就是一个麻烦。此时,您的Hibernate会话应该仍然处于打开状态,无论是否筛选


你能发布你的DAO代码和相关的配置吗?

如果你的代码在控制器中失败了,那么过滤器就是一个麻烦。此时,您的Hibernate会话应该仍然处于打开状态,无论是否筛选


您能发布DAO代码和相关配置吗?

迪克是正确的,控制器类可能在做一些有趣的事情

另一点是确保在类路径中有所有必需的jar,例如cglib或javaassist

使用springs OpenSessionInviewWinterCeptor而不是OpenSessionInViewFilter可能更容易,因为您已经在使用spring了

只需在blog-servlet.xml配置中添加以下内容,您当然可以将其拆分为多个文件

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors"><list>    
        <ref bean="openSessionInViewInterceptor" />             
    </list></property>
</bean>
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
    <property name="entityManagerFactory"><ref local="entityManagerFactory"/></property>    
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="ha-admin" />
    <property name="dataSource"  ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"  
            p:database="ORACLE" p:showSql="true" />
    </property>

    <property name="jpaPropertyMap">
    <props>                 


         <!-- Enable Hibernate statistics generation 
         <prop key="hibernate.cache.use_query_cache">true</prop>
         <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
         <prop key="hibernate.cache.use_second_level_cache">true</prop>
         <prop key="hibernate.cache.provider_configuration_file_resource_path">/ehcache.xml</prop>
        <prop key="hibernate.generate_statistics">true</prop>
        -->                                             
    </props>        
    </property>
</bean>

您需要在配置文件中添加数据源,并从web.xml中删除hibernateFilter。

迪克是正确的,控制器类可能在做一些有趣的事情

另一点是确保在类路径中有所有必需的jar,例如cglib或javaassist

使用springs OpenSessionInviewWinterCeptor而不是OpenSessionInViewFilter可能更容易,因为您已经在使用spring了

只需在blog-servlet.xml配置中添加以下内容,您当然可以将其拆分为多个文件

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors"><list>    
        <ref bean="openSessionInViewInterceptor" />             
    </list></property>
</bean>
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
    <property name="entityManagerFactory"><ref local="entityManagerFactory"/></property>    
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="ha-admin" />
    <property name="dataSource"  ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"  
            p:database="ORACLE" p:showSql="true" />
    </property>

    <property name="jpaPropertyMap">
    <props>                 


         <!-- Enable Hibernate statistics generation 
         <prop key="hibernate.cache.use_query_cache">true</prop>
         <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
         <prop key="hibernate.cache.use_second_level_cache">true</prop>
         <prop key="hibernate.cache.provider_configuration_file_resource_path">/ehcache.xml</prop>
        <prop key="hibernate.generate_statistics">true</prop>
        -->                                             
    </props>        
    </property>
</bean>

您需要在配置文件中添加数据源,并从web.xml中删除hibernateFilter。

您说过,当您急切地加载集合对象时,应用程序运行良好

由于您使用的是来自另一个请求的httpsession的用户对象,因此可能必须使用refresh或update重新附加该用户对象

以下代码有效吗

User u = (User) session.getAttribute("currentUser");

User newUser = service.getUser(u.getUserId);
System.out.println(newUser.getBlogs());
看看这是否有帮助。你能在你的类路径中列出jar文件吗

<filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>singleSession</param-name>
        <param-value>true</param-value> <!-- or false -->
    </init-param>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>openSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

您说过,当您急切地加载集合对象时,应用程序运行良好

由于您使用的是来自另一个请求的httpsession的用户对象,因此可能必须使用refresh或update重新附加该用户对象

以下代码有效吗

User u = (User) session.getAttribute("currentUser");

User newUser = service.getUser(u.getUserId);
System.out.println(newUser.getBlogs());
看看这是否有帮助。你能在你的类路径中列出jar文件吗

<filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>singleSession</param-name>
        <param-value>true</param-value> <!-- or false -->
    </init-param>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>openSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

嗯,也许在这个阶段你不会改变你的ORM——但这很好地提醒了我们为什么无会话ORM很有趣


e、 艾比安·奥姆。。。没有会话,延迟加载只起作用,不需要过滤器-意味着您永远不会遇到这个问题。

Hmmm,可能您在这个阶段不会更改您的ORM-但这很好地提醒了我们为什么无会话ORM很有趣


e、 艾比安·奥姆。。。没有会话,延迟加载只起作用,不需要过滤器-意味着您永远不会遇到这个问题。

只是一个想法:对我来说,它有助于更改过滤器的顺序。我有一个url重写过滤器,会话过滤器的顺序很重要


只是一个想法……

只是一个想法:对我来说,这有助于改变过滤器的顺序。我有一个url重写过滤器,会话过滤器的顺序很重要


只是想一想…

重新实现OpenSessionInViewFilter不是解决方案。回到使用Spring one,然后向我们展示您的控制器代码和JSP,异常堆栈trace.Re-implementing OpenSessionInViewFilter不是解决方案。回到使用Spring one,然后向我们展示您的控制器代码和JSP,以及异常堆栈跟踪。。我使用session来识别当前用户…但最初我只使用默认的OpenSessionViewFilter方法…但即使这样也没有帮助你说得对,所有问题的根源不是早期优化,而是分离的对象!你说得对。。我使用session来识别当前用户…但最初我只使用默认的OpenSessionViewFilter方法…但即使这样也没有帮助你说得对,所有问题的根源不是早期优化,而是分离的对象!如果您的代码确实在添加注释时失败,那么在DAO中调用findById时必须关闭hibernate会话。我还没有看到您的DAO代码,请发布此消息。如果您的代码确实在添加注释时失败,则必须在DAO中调用findById时关闭hibernate会话。我还没有看到你的DAO代码,请发布这个。嘿,非常感谢:我删除了过滤器并实现了拦截器。现在它工作正常了。谢谢。太好了。拦截器是一种更好的方法,因为您可以在web类之外对其进行测试。嘿,非常感谢:我删除了过滤器并实现了拦截器。现在它工作正常了。谢谢。太好了。拦截器是一种更好的方法,因为您可以在web类之外对其进行测试。。