Spring Hibernate事务没有会话延迟加载

时间:2013-05-28 22:03:56

标签: spring hibernate

我遇到的问题是只有一个控制器有一个延迟加载的实体(启动并提交了一个事务,请参阅堆栈跟踪)

17:56:46,084 DEBUG HibernateTransactionManager:438 - Found thread-bound Session [org.hibernate.impl.SessionImpl@6b204e88] for Hibernate transaction
17:56:46,085 DEBUG HibernateTransactionManager:471 - Participating in existing transaction
17:56:46,085 DEBUG HibernateTransactionManager:438 - Found thread-bound Session [org.hibernate.impl.SessionImpl@6b204e88] for Hibernate transaction
17:56:46,085 DEBUG HibernateTransactionManager:471 - Participating in existing transaction
Hibernate: select preference0_.id as id66_, preference0_.name as name66_, preference0_.value as value66_, preference0_.default_value as default4_66_, preference0_.updated_at as updated5_66_ from preferences preference0_ where preference0_.name='scheduleInterval'
17:56:46,086 DEBUG GooGooStatementCache:457 - cxnStmtMgr.statementSet( com.mysql.jdbc.JDBC4Connection@5ec60ee2 ).size(): 21
17:56:46,086 DEBUG GooGooStatementCache:196 - checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 111; checked out: 1; num connections: 10; num keys: 111
17:56:46,087 DEBUG GooGooStatementCache:271 - checkinStatement(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 111; checked out: 0; num connections: 10; num keys: 111
17:56:46,089 FATAL app:79 - service
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.model.User_$$_javassist_76.getName(User_$$_javassist_76.java)
    at com.model.json.ScheduleItemWrapper.wrap(ScheduleItemWrapper.java:55)
    at com.web.controllers.ajax.Model.wrap(Model.java:127)
    at com.web.controllers.ajax.Model.toJSON(Model.java:165)
    at com.web.controllers.ajax.Model.getContent(Model.java:51)
    at com.web.controllers.ajax.BasicAction.execute(BasicAction.java:27)
    at com.web.HibernateServlet.doService(HibernateServlet.java:113)
    at com.web.HibernateServlet.service(HibernateServlet.java:66)
    at sun.reflect.GeneratedMethodAccessor200.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:695)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    at com.levitech.web.controllers.schedule.ScheduleList$$EnhancerByCGLIB$$4a7ae33e.service(<generated>)
    at com.levitech.web.RequestDispatcher.service(RequestDispatcher.java:63)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:662)
17:56:46,090 DEBUG HibernateTransactionManager:753 - Initiating transaction commit
17:56:46,090 DEBUG HibernateTransactionManager:653 - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@6b204e88]
17:56:46,091 DEBUG HibernateTransactionManager:735 - Closing Hibernate Session [org.hibernate.impl.SessionImpl@6b204e88] after transaction
17:56:46,091 DEBUG SessionFactoryUtils:800 - Closing Hibernate Session

模型(ScheduleItem和User)及其hibernate映射

public class ScheduleItem {
  private Integer id;
  ....
  private User user;

}

public class User {
  private Integer id;
  ...
  private String name;

}

<class 
    name="ScheduleItem" 
    table="schedule_item"
>

    <cache usage="read-write"/>


    <id
        name="id"
        type="integer"
        column="id"
    >
    <generator class="identity" />
    </id>
    <many-to-one name="user" column="user_id" lazy="proxy"></many-to-one>
</class>

<class 
    name="ScheduleItem" 
    table="schedule_item"
>

    <cache usage="read-write"/>


    <id
        name="id"
        type="integer"
        column="id"
    >
    <generator class="identity" />
    </id>
    <property name="name" column="name" type="string" />
</class>

我找到了罪魁祸首。 OpenSessionViewFilter使用不同的会话或sessionfactory。

这是我的Spring配置和web.xml(我做错了什么?):

web.xml的一部分:

<filter>
      <filter-name>hibernateFilter</filter-name>
      <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
      <init-param>
         <param-name>sessionFactoryBeanName</param-name>
         <param-value>sessionFactory</param-value>         
      </init-param>      
   </filter>

   <filter-mapping>
     <filter-name>hibernateFilter</filter-name>
     <url-pattern>/app/s/*</url-pattern>
   </filter-mapping> 

Spring Config的一部分:

<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
     <property name="driverClass" value="${db.driver}"/>
     <property name="jdbcUrl" value="${db.url}"/>
     <property name="user" value="${db.user}"/>
     <property name="password" value="${db.pass}"/>

       <!-- Pool properties -->
     <property name="minPoolSize" value="5" />
     <property name="maxPoolSize" value="100" />
     <property name="acquireIncrement" value="5" />
     <property name="maxStatements" value="200" />
     <property name="idleConnectionTestPeriod" value="120" />
     <property name="maxIdleTime" value="1800" />

  </bean>

      <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"></property>
         <property name="mappingLocations" value="classpath*:com/model/hbm/**/*.hbm.xml" />

    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
        hibernate.show_sql=true
        hibernate.cache.region.factory_class=net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory
        hibernate.cache.use_query_cache=true
        hibernate.cache.use_second_level_cache=true
      </value>
    </property>
      </bean>

      <bean id="transactionManager"
                class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
      </bean>

3 个答案:

答案 0 :(得分:2)

您的问题有多种解决方案:

  • 最简单的是使用Spring的OpenSessionInViewFilter。只需将此过滤条件添加到web.xml并将其配置为过滤您的请求即可。 此过滤器在过滤器中打开和关闭Hibernate会话,因此在页面呈现期间会打开。

  • 有些人认为OpenSessionInViewFilter反对良好的设计,它将业务逻辑混合到表示层。如果您这么认为,请在查询中获取引用的对象(例如,在HQL中使用join fetch)。

答案 1 :(得分:2)

从日志中看,当您收到此异常时,会话仍处于打开状态。您将获得此类异常的另一种情况是数据库中是否存在该行。

User user = session.load(User.class, 1000); // Create a proxy
user.getName(); // This would throw lazy initialization exception if row doesn't exist

可能导致此问题的另一个方案是使用分离的对象。如果您将ScheduleItem作为HTTPSession变量获取并存储。在另一个请求中检索它,然后尝试访问代理 - 它将导致相同的异常。用于加载对象的会话已关闭。如果是这种情况,您需要在使用之前首先将对象重新附加到新会话(合并,更新或锁定)。

答案 2 :(得分:-1)

您可以尝试:

  • 急切加载该系列。
  • 在离开集合之前通过调用相应的getter方法Hibernate.initialize(rtn.getUserRoles());
  • 来初始化集合

这基本上是相同方法的两倍,具体取决于您的设置中最有效的方法。您确保在离开会话之前加载完整实体,使实体可以与旧实体分离,然后重新连接到新会话而不会出现问题。您正在做的是在离开会话之前初始化代理,以便在您不在会话上下文时确保可以使用该集合。