failed to lazily initialize a collection of role: no session or session was closed

时间:2022-12-14 20:33:58
我在启动TOMCAT 通过一个来初始化一些数据,碰到了这么一个问题,启动后访问都很正常,就是启动时出现这种问题。

在init 方法中如下:
ServletContext scx = getServletContext();
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(scx);
CustomListManager customListManager =(CustomListManager)wac.getBean("customListManager");
List<CustomList> customLists = customListManager.getAll();

customLists 这个对象取到了customlist表中的所有记录,这里都很正常,但是接下出现了一奇怪的问题

在getItems()时,出现了org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.aata.setup.CustomList.items, no session or session was closed
不清楚,什么关闭session的,我的session是由OpenSessionInViewFilter控制的。
for(CustomList customList:customLists){
System.out.print(customList.getItems().size());
}


InitServlet.java

package com.aata.web.common;

import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.aata.setup.CustomList;
import com.aata.setup.CustomListCache;
import com.aata.setup.CustomListManager;

public class InitServlet extends HttpServlet {

private static final long serialVersionUID = 102294050344951035L;

@Override
public void init() throws ServletException {
ServletContext scx = getServletContext();

WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(scx);

CustomListManager customListManager =(CustomListManager)wac.getBean("customListManager");
List<CustomList> customLists = customListManager.getAll();
for(CustomList customList:customLists){
System.out.print(customList.getItems().size());
}


CustomListCache.init(customListManager.getAll());


CustomList country = CustomListCache.getCustomList(CustomListCache.COUNTRY);
CustomList state   = CustomListCache.getCustomList(CustomListCache.STATE);


//set to servlet context

scx.setAttribute("countryList", country.getItems());
scx.setAttribute("stateList", state.getItems());
}
}

20 个解决方案

#1


Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!-- Spring ApplicationContext -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/*.xml</param-value>
</context-param>

<!-- i18n -->
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>i18n/messages</param-value>
</context-param>

<!-- Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--Hibernate Open Session in View Filter-->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>

<filter>
        <filter-name>struts-cleanup</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
    </filter>
    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
<filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>



<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>

</filter-mapping>

    <filter-mapping>
        <filter-name>struts-cleanup</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

<!--Spring ApplicationContextx-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Spring Introspector-->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

  <servlet>
    <servlet-name>init</servlet-name>
    <servlet-class>com.aata.web.common.InitServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>


  <servlet>
    <servlet-name>AddBusiness</servlet-name>
    <servlet-class>com.aata.web.front.AddBusinessServlet</servlet-class>
  </servlet>
  
  <servlet>
    <servlet-name>Index</servlet-name>
    <servlet-class>com.aata.web.front.IndexServlet</servlet-class>
   </servlet>

  <servlet>
    <servlet-name>MapSearch</servlet-name>
    <servlet-class>com.aata.web.front.MapSearchServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>Login</servlet-name>
    <servlet-class>com.aata.web.front.LoginServlet</servlet-class>
  </servlet>
  

  <servlet-mapping>
    <servlet-name>AddBusiness</servlet-name>
    <url-pattern>/add_business.html</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>
    <servlet-name>Index</servlet-name>
    <url-pattern>/index.html</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>MapSearch</servlet-name>
    <url-pattern>/search.html</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Login</servlet-name>
    <url-pattern>/login.html</url-pattern>
  </servlet-mapping>



  
  
<!-- session time out -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>

<!-- welcome list -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<!-- Error Page -->
<error-page>
<error-code>500</error-code>
<location>/commons/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/commons/404.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/commons/403.jsp</location>
</error-page>  
</web-app>



spring配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-autowire="byName" default-lazy-init="true">

<!-- 数据源定义,使用Apache DBCP 连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<!--Hibernate SessionFatory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>com.aata.business.Business</value>
<value>com.aata.customer.Customer</value>
<value>com.aata.setup.CustomList</value>
<value>com.aata.setup.CustomListItem</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>

<!--Hibernate TransactionManager-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>


#2


集合延迟加载了,把lazy改成false,或者使用OpenSessionInView

#3


把mapping文件里面的set那部分的lazy设置为false

#4


我的lazy是设为true的,我要用到lazy这个机制,但我是使用OpenSessionInViewFilter 的,怎么在读items时,session被close了。

#5


lazy=false

#6


我需要用Lazy机制

#7


什么原因使OpenSessionInViewFilter 关闭了我的session

#8


你可以先把你要取得东西初始化一下
最直接的就是先调用他一下
也可以
if(!Hibernate.isInitialized(ob)){
 Hibernate.initialize(ob);
}
先判断是否已经被填充
没有的话就填充

#9


你的代码是在init方法里,和OpenSessionInViewFilter没关系阿。filter是在请求的范围内工作,init的时候没有请求,filter当然啥也不知道啦。
自己控制session的open和close吧,别指望filter能给你关闭连接

#10


steven_cheng,我也查了我在init 时不是filter给的session,我在filter该如何获取session能够使用CustomListManager 这个类。

//是不是不能用我现在的方法

ServletContext scx = getServletContext();

WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(scx);

CustomListManager customListManager =(CustomListManager)wac.getBean("customListManager");

#11


init是在servlet初始化的时候调用,当然没有经过filter了,应该把那坨代码放在doGet或者doPost方法里面,然后在浏览器调用这个servlet

#12


我这个Servlet 是用来在tomcat 启动初始化一些数据的,所以没有get,post之类的方法

有没有好的方法啊,解决这个问题。

#13


既然filter能够open、close Session,当然你也可以啊,看看filter里怎么写的,照猫画虎不就知道啦:D现在只是你不能指望在init方法里filter给你管理session,你必须手动的打开一个session,用完以后close。这样是代价最小的修改,其他代码不需要改。

#14


既然是初始化一些东西,那就自己写hibernate了,不用spring来托管

#15


楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"

#16


ding 

#17


学习!!!!!!!!!!

#18


http://blog.sina.com.cn/s/blog_5e2d8c740100jduy.html

#19


引用 15 楼 eason26_li 的回复:
楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"



这位仁兄说的很对,我尝试了不报session close 了

#20


引用 19 楼 super_han 的回复:
引用 15 楼 eason26_li 的回复:

楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"



这位仁兄说的很对,我尝试了不报session close 了


但是join会出现N+1的问题,怎么处理

#1


Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!-- Spring ApplicationContext -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/*.xml</param-value>
</context-param>

<!-- i18n -->
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>i18n/messages</param-value>
</context-param>

<!-- Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--Hibernate Open Session in View Filter-->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>

<filter>
        <filter-name>struts-cleanup</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
    </filter>
    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
<filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>



<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>

</filter-mapping>

    <filter-mapping>
        <filter-name>struts-cleanup</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

<!--Spring ApplicationContextx-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Spring Introspector-->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

  <servlet>
    <servlet-name>init</servlet-name>
    <servlet-class>com.aata.web.common.InitServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>


  <servlet>
    <servlet-name>AddBusiness</servlet-name>
    <servlet-class>com.aata.web.front.AddBusinessServlet</servlet-class>
  </servlet>
  
  <servlet>
    <servlet-name>Index</servlet-name>
    <servlet-class>com.aata.web.front.IndexServlet</servlet-class>
   </servlet>

  <servlet>
    <servlet-name>MapSearch</servlet-name>
    <servlet-class>com.aata.web.front.MapSearchServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>Login</servlet-name>
    <servlet-class>com.aata.web.front.LoginServlet</servlet-class>
  </servlet>
  

  <servlet-mapping>
    <servlet-name>AddBusiness</servlet-name>
    <url-pattern>/add_business.html</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>
    <servlet-name>Index</servlet-name>
    <url-pattern>/index.html</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>MapSearch</servlet-name>
    <url-pattern>/search.html</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Login</servlet-name>
    <url-pattern>/login.html</url-pattern>
  </servlet-mapping>



  
  
<!-- session time out -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>

<!-- welcome list -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<!-- Error Page -->
<error-page>
<error-code>500</error-code>
<location>/commons/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/commons/404.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/commons/403.jsp</location>
</error-page>  
</web-app>



spring配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-autowire="byName" default-lazy-init="true">

<!-- 数据源定义,使用Apache DBCP 连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<!--Hibernate SessionFatory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>com.aata.business.Business</value>
<value>com.aata.customer.Customer</value>
<value>com.aata.setup.CustomList</value>
<value>com.aata.setup.CustomListItem</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>

<!--Hibernate TransactionManager-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>


#2


集合延迟加载了,把lazy改成false,或者使用OpenSessionInView

#3


把mapping文件里面的set那部分的lazy设置为false

#4


我的lazy是设为true的,我要用到lazy这个机制,但我是使用OpenSessionInViewFilter 的,怎么在读items时,session被close了。

#5


lazy=false

#6


我需要用Lazy机制

#7


什么原因使OpenSessionInViewFilter 关闭了我的session

#8


你可以先把你要取得东西初始化一下
最直接的就是先调用他一下
也可以
if(!Hibernate.isInitialized(ob)){
 Hibernate.initialize(ob);
}
先判断是否已经被填充
没有的话就填充

#9


你的代码是在init方法里,和OpenSessionInViewFilter没关系阿。filter是在请求的范围内工作,init的时候没有请求,filter当然啥也不知道啦。
自己控制session的open和close吧,别指望filter能给你关闭连接

#10


steven_cheng,我也查了我在init 时不是filter给的session,我在filter该如何获取session能够使用CustomListManager 这个类。

//是不是不能用我现在的方法

ServletContext scx = getServletContext();

WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(scx);

CustomListManager customListManager =(CustomListManager)wac.getBean("customListManager");

#11


init是在servlet初始化的时候调用,当然没有经过filter了,应该把那坨代码放在doGet或者doPost方法里面,然后在浏览器调用这个servlet

#12


我这个Servlet 是用来在tomcat 启动初始化一些数据的,所以没有get,post之类的方法

有没有好的方法啊,解决这个问题。

#13


既然filter能够open、close Session,当然你也可以啊,看看filter里怎么写的,照猫画虎不就知道啦:D现在只是你不能指望在init方法里filter给你管理session,你必须手动的打开一个session,用完以后close。这样是代价最小的修改,其他代码不需要改。

#14


既然是初始化一些东西,那就自己写hibernate了,不用spring来托管

#15


楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"

#16


ding 

#17


学习!!!!!!!!!!

#18


http://blog.sina.com.cn/s/blog_5e2d8c740100jduy.html

#19


引用 15 楼 eason26_li 的回复:
楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"



这位仁兄说的很对,我尝试了不报session close 了

#20


引用 19 楼 super_han 的回复:
引用 15 楼 eason26_li 的回复:

楼主只要设置customList 对getItems()对象的<set>设置属性为预先抓取就可以解决该问题fetch="join"



这位仁兄说的很对,我尝试了不报session close 了


但是join会出现N+1的问题,怎么处理

#21