事务影响懒加载 no session or session was closed

公司跑批时,因原先事务配置删除,访问数据库拿到数据后就关闭session,导致懒加载无法正常进行并报错。懒加载需用到数据时才去数据库加载,而关闭的session无法实现此功能。加回事务配置后,session不再用完即关,问题得以解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

公司有个跑批,原先的事务配置删了,导致访问数据库拿到数据后就关了session

众所周知,懒加载就是用到该数据时才去数据库加载,但session都关了,还谈何加载,并报了下面这个错

 

2019-05-28 09:45:00,191 cn.com.sinosoft.job.StaffWelfareInsuredJob.doJob(StaffWelfareInsuredJob.java:98) INFO   -员工福利承保任务:进行承保操作。订单号为:B0001552097
2019-05-28 09:45:00,191 org.hibernate.LazyInitializationException.<init>(LazyInitializationException.java:42) ERROR  -failed to lazily initialize a collection of role: cn.com.sinosoft.iecs.online.domain.sale.GeStaffPolicy.geStaffInfos, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.com.sinosoft.iecs.online.domain.sale.GeStaffPolicy.geStaffInfos, no session or session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
	at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
	at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
	at cn.com.sinosoft.iecs.online.sale.service.impl.StaffWelfareSaleServiceImpl.getStaffWelfareInfo(StaffWelfareSaleServiceImpl.java:96)
	at cn.com.sinosoft.job.StaffWelfareInsuredJob.doJob(StaffWelfareInsuredJob.java:99)
	at sun.reflect.GeneratedMethodAccessor12895.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:269)
	at cn.com.sinosoft.springframework.scheduling.quartz.BeanInvokingJobDetailFactoryBean$BeanInvokingJob.execute(BeanInvokingJobDetailFactoryBean.java:486)
	at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)

加回事务配置后,session不再是用完就关,问题解决。

@Transactional(value="transactionManager",isolation=Isolation.READ_UNCOMMITTED)

 

转载于:https://my.oschina.net/u/2277088/blog/3056344

<think>嗯,我现在遇到了Hibernate中的LazyInitializationException异常,提示“no session or session was closed”。这个问题让我有点困惑,我得仔细想想怎么解决它。首先,我需要理解这个异常为什么会发生。 根据引用里的内容,Hibernate在查询操作完成后会自动关闭session,而延迟加载(Lazy Loading)的特性会导致在session关闭后尝试访问未加载的关联对象时抛出这个异常。比如,我有一个实体类ProductType,它有一个childtypes的集合属性,这个属性被设置为延迟加载。当Hibernate从数据库获取ProductType对象后,session被关闭了,之后如果代码试图访问childtypes,就会触发这个异常,因为session已经不可用了。 那么,解决这个问题的思路是什么呢?引用里提到了几种方法。首先,关闭延迟加载特性。不过这样做可能会影响性能,因为会立即加载所有关联数据,特别是当关联数据量大时,会增加数据库的负担。所以这个方法可能不是最优的。 另一种方法是延长session的生命周期,确保在需要访问关联对象时session仍然打开。比如使用Open Session in View模式,这在Web应用中比较常见。通过在请求开始时打开session,在视图渲染结束后关闭,这样在渲染过程中访问延迟加载的属性就不会出问题了。引用里的OpenSessionInViewFilter就是一个例子,不过代码示例中的过滤器似乎是在处理完请求之后关闭session,可能需要调整过滤器的执行顺序,确保在视图渲染前session是打开的,之后才关闭。 另外,还可以在查询时使用Hibernate的Fetch Join来主动加载关联数据,比如HQL中使用JOIN FETCH或者Criteria API中的setFetchMode。这样,在查询主实体时,关联的集合会被立即加载,避免了延迟加载的问题。这种方法适用于明确知道需要哪些关联数据的场景。 还有一种方法是使用Hibernate.initialize()方法,在session关闭前手动初始化代理对象。比如在获取到ProductType对象后,调用Hibernate.initialize(productType.getChildtypes()),这样childtypes集合会被立即加载,之后即使session关闭,数据也已经存在了。 此外,调整事务边界也是一种解决方式。确保在业务逻辑层中完成所有需要访问延迟加载属性的操作,而不是在表示层(如JSP页面)中处理。这样,在事务尚未提交、session仍处于打开状态时,就能访问到关联数据。 现在需要综合这些方法,选择适合当前应用场景的解决方案。比如在Web应用中,使用Open Session in View模式比较方便,但需要注意潜在的性能问题。如果应用结构分层清晰,可能更适合在服务层中通过Fetch Join或Hibernate.initialize()来预先加载所需数据,避免在视图层处理数据加载。 另外,检查Hibernate的配置是否正确,比如是否启用了延迟加载,以及是否有其他配置影响session的生命周期。例如,使用Spring框架的话,可以通过配置OpenSessionInViewFilter或OpenSessionInViewInterceptor来管理session的生命周期。 总结一下,可能的解决方案有: 1. 使用Fetch Join主动加载关联数据。 2. 在session关闭前手动初始化代理对象。 3. 配置Open Session in View模式延长session生命周期。 4. 调整事务边界,确保在session打开时访问延迟加载属性。 5. 关闭延迟加载(不推荐,影响性能)。 需要根据具体情况选择合适的方法。比如,如果问题出现在JSP页面渲染时,可能适合用Open Session in View;如果在业务逻辑中已知需要访问某些关联数据,使用Fetch Join更高效。</think>### 如何解决 Hibernate LazyInitializationException 异常(no session or session was closed)? #### 问题原因 该异常是由于Hibernate的**延迟加载(Lazy Loading)**特性与**Session生命周期不匹配**导致的。当通过`get()`或`load()`方法获取实体后,如果Session已关闭,再尝试访问未加载的延迟关联对象(如集合属性),就会触发`LazyInitializationException`[^3][^5]。 --- #### 解决方案(逐步分析) ##### 1. **使用`JOIN FETCH`主动加载关联数据** 在查询时通过HQL或Criteria API**立即加载所需关联数据**,避免延迟加载。 ```java // HQL示例:使用JOIN FETCH加载childtypes String hql = "SELECT pt FROM ProductType pt JOIN FETCH pt.childtypes WHERE pt.id = :id"; Query query = session.createQuery(hql).setParameter("id", 1); ProductType productType = (ProductType) query.uniqueResult(); ``` - **优点**:精确控制加载范围,减少数据库冗余查询。 - **缺点**:需提前明确需要加载的关联字段。 ##### 2. **手动初始化代理对象** 在Session关闭前,通过`Hibernate.initialize()`强制加载延迟集合: ```java ProductType productType = session.get(ProductType.class, 1); Hibernate.initialize(productType.getChildtypes()); // 手动初始化集合 session.close(); // 后续代码可安全访问childtypes ``` - **适用场景**:明确知道需要访问哪些关联对象。 ##### 3. **配置Open Session in View模式** 在Web应用中,通过过滤器或拦截器**延长Session生命周期至视图渲染完成**,确保页面渲染时Session仍处于打开状态。 **Spring配置示例**: ```xml <!-- web.xml中配置OpenSessionInViewFilter --> <filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值