解决org.hibernate.LazyInitializationException的正确姿势
项目运行过程中,一个报错信息,报错信息如下:
org.hibernate.LazyInitializationException: could not initialize proxy [xxx.domain.Guild#CF12263C600F4BCABC9293D3FABE4B42] - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169) ~[hibernate-core-5.3.9.Final.jar!/:5.3.9.Final]
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309) ~[hibernate-core-5.3.9.Final.jar!/:5.3.9.Final]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45) ~[hibernate-core-5.3.9.Final.jar!/:5.3.9.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.3.9.Final.jar!/:5.3.9.Final]
at xxx.domain.Guild$HibernateProxy$58NSae2j.getName(Unknown Source) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.task.TaskJiaoFuService.guildName(TaskJiaoFuService.java:181) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.task.TaskJiaoFuService.result2JiaoFuDetail(TaskJiaoFuService.java:122) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.task.TaskJiaoFuService.parseResult(TaskJiaoFuService.java:106) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.task.TaskJiaoFuService.queryV4(TaskJiaoFuService.java:91) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.AbstractExportStrategy.query(AbstractExportStrategy.java:65) ~[classes!/:0.0.9-SNAPSHOT]
at xxx.ExportService.exportAndPersistence(ExportService.java:130) [classes!/:0.0.9-SNAPSHOT]
at xxx.ExportService.lambda$execute$0(ExportService.java:75) [classes!/:0.0.9-SNAPSHOT]
at xxx.common.initialization.ContextCopyingTaskDecorator.lambda$decorate$0(ContextCopyingTaskDecorator.java:20) ~[classes!/:0.0.9-SNAPSHOT]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_181]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_181]
业务很简单,一个jpa的单表查询,获取属性的时候报错了
分析
JPA默认使用的懒加载,即使访问的是单个实体类,返回的对象也是代理,在获取对象属性的时候才会进行数据库查询,此时如果连接数据session已释放则会抛出上述异常
org.hibernate.LazyInitializationException在经常使用hibernate或者jpa的同学中可能经常遇到,网络上一搜,解决问题的方式有很多种,这里罗列一下:
- 在spring boot的配置文件application.properties添加spring.jpa.open-in-view=true
- 用spring 的OpenSessionInViewFilter
- 在spring boot的配置文件application.properties添加spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
- 在出问题的实体类上加@Proxy(lazy = false)
- ……
spring.jpa.open-in-view
我们看下baeldung上是怎么说的,传送门:https://www.baeldung.com/spring-open-session-in-view
Session per request is a transactional pattern to tie the persistence session and request life-cycles together. Not surprisingly, Spring comes with its own implementation of this pattern, named OpenSessionInViewInterceptor, to facilitate working with lazy associations and therefore, improving developer productivity.
………
By default, OSIV is active in Spring Boot applications. Despite that, as of Spring Boot 2.0, it warns us of the fact that it's enabled at application startup if we haven't configured it explicitly:
spring.jpa.open-in-view is enabled by default. Therefore, database
queries may be performed during view rendering.Explicitly configure
spring.jpa.open-in-view to disable this warning
意思大致是,每个请求会话对于Spring来说都是一种事务模式,所以了我们默认给你开启了,用于提高开发效率,不过你如果没有显式配置的话,我还会给你一个warning告警。关于这个默认配置在github上争论也有不少:https://github.com/spring-projects/spring-boot/issues/7107
OSIV时序图如下:

项目中spring.jpa.open-in-view是设置为false的,代码获取实体类或者关联实体都是service中完成的,一般我们开启事务,在事务作用的上下文环境中去获取懒加载的数据是不会有任何问题的,且开启之后数据的session会等到整个request完成之后才会释放,其实是十分消耗性能的,之前有其他同学没有关闭open-in-view遇到的问题:https://www.cnblogs.com/thisismarc/p/13594399.html
结论:spring.jpa.open-in-view为true可以解决报错,不过不推荐,OpenSessionInViewFilter配置方案也PASS
spring.jpa.properties.hibernate.enable_lazy_load_no_trans
我们也看下baeldung上是怎么说的,传送门:https://www.baeldung.com/hibernate-lazy-loading-workaround
While using lazy loading in Hibernate, we might face exceptions, saying there is no session.
……
The recommended approach is to design our application to ensure that data retrieval happens in a single transaction. But, this can sometimes be difficult when using a lazy entity in another part of the code that is unable to determine what has or hasn't been loaded.
Hibernate has a workaround, an enable_lazy_load_no_trans property. Turning this on means that each fetch of a lazy entity will open a temporary session and run inside a separate transaction.
意思大致是,这是一种变通的做法,可以为每个懒加载的实体打开一个临时的会话,不过这个方法也是反人类的,因为如果延迟加载的关联实体越多,请求附加的连接也就越多,这会给数据库连接带来压力。在新事务中加载的每个关联,在每次关联初始化后都会强制刷新事务日志,所以大大的不建议使用。
@Proxy(lazy = false)
@Proxy(lazy = false)的意思和FetchType.EAGER类似,返回的是初始化好的实体,即关闭了懒加载,这个肯定不是我们想要的
推荐解决方式
回到我们的问题,单表懒加载报错,项目使用的是Springboot,事务都是显式的注解配置,查询的接口我们一般没有配置@Transactional注解,所以解决方法是在Service的查询方法上增加 @Transactional(readOnly = true) 注解来划分事务边界,这是比较推荐的做法,也复合编码规范,项目中如果有事务切面配置,把相关方法加到事务控制的范围中则也不会出现这个问题,如果还有其他更好的方式,欢迎留言
参考链接
https://vladmihalcea.com/the-hibernate-enable_lazy_load_no_trans-anti-pattern/
https://www.baeldung.com/spring-open-session-in-view
https://github.com/spring-projects/spring-boot/issues/7107
https://www.cnblogs.com/thisismarc/p/13594399.html
https://www.baeldung.com/hibernate-lazy-loading-workaround
解决org.hibernate.LazyInitializationException的正确姿势的更多相关文章
- 【bug记录】jpa 解决org.hibernate.lazyinitializationexception could not initialize proxy - no session
前言 最近开发项目比较忙,Spring Cloud的笔记得稍稍放放了,下午出来个bug,恶心的不行,功能很简单,也没有什么级联或复杂的映射关系,就是一直在报三个异常 Caused by: com.fa ...
- 解决org.hibernate.LazyInitializationException: could not initialize proxy - no Session懒载入问题
问题描写叙述: Struts Problem Report Struts has detected an unhandled exception: Messages: could not initia ...
- jpa 解决org.hibernate.lazyinitializationexception could not initialize proxy - no session
org.hibernate.LazyInitializationException: could not initialize proxy [org.alan.entity.SysUser#1] - ...
- 剖析和解决Python中网络粘包的正确姿势
目录 1.粘包及其成因 1.1.粘包产生 1.2.粘包产生的原因 2.尝试解决粘包 2.1.指定数据包的长度 2.2.固定数据包的长度 2.3.用函数实现多次调用发送数据 3.解决粘包问题的正确姿势 ...
- dubbo序列化hibernate.LazyInitializationException could not initialize proxy - no Session懒加载异常的解决
dubbo序列化,hibernate.LazyInitializationException could not initialize proxy - no Session懒加载异常的解决 转载声明: ...
- 总结懒加载的解决方法(全)org.hibernate.LazyInitializationException: could not initialize proxy - no Session
如下错误:org.hibernate.LazyInitializationException: could not initialize proxy - no Session 原因是懒加载的问题,因为 ...
- Ubuntu 解决wifi无法打开的问题 安装NVIDIA显卡驱动的正确姿势
游戏本型号Y7000 win10 Ubuntu16.04双系统 解决wifi无法打开的问题 解决方法: 1.打开终端输入:rfkill list all 出现如下提示:: 可以看到,优先级 ...
- org.hibernate.LazyInitializationException异常解决办法
org.hibernate.LazyInitializationException异常failed to lazily initialize a collection...的解决方案使用hiberna ...
- 在Linux(ubuntu server)上面安装NodeJS的正确姿势
上一篇文章,我介绍了 在Windows中安装NodeJS的正确姿势,这一篇,我们继续来看一下在Linux上面安装和配置NodeJS. 为了保持一致,这里也列举三个方法 第一个方法:通过官网下载安装 h ...
随机推荐
- 【NX二次开发】Block UI对话框-代码生成部分
常规: 语言:生成的代码语言 生成附注:是否生成注释代码 生成特定与块的代码: 输入点: 回调:对话框通过回调函数调用,例如通过另一个对话框的按钮调用本对话框 菜单:对话框通过菜单调用 用户出口:对话 ...
- 可微渲染 SoftRas 实践
SoftRas 是目前主流三角网格可微渲染器之一. 可微渲染通过计算渲染过程的导数,使得从单张图片学习三维结构逐渐成为现实.可微渲染目前被广泛地应用于三维重建,特别是人体重建.人脸重建和三维属性估计等 ...
- 痞子衡嵌入式:Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link/DAPLink)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 本篇是 <IAR EWARM复位类型>.<M ...
- 【题解】覆盖问题 BZOJ1052 HAOI2007 二分
题目描述 某 人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定用 3个LL的正方形塑料薄膜将小树遮起来.我 ...
- 小白学k8s(9)-gitlab-runner实现go项目的自动化发布
gitlab构建CI/CD 准备 docker部署gitlab 使用二进制部署gitlab-runner gitlab-runner注册 配置Variables 简单先来个测试 开始构建 遇到的报错 ...
- Electron-Vite2-MacUI桌面管理框架|electron13+vue3.x仿mac桌面UI
基于vue3.0.11+electron13仿制macOS桌面UI管理系统ElectronVue3MacUI. 前段时间有分享一个vue3结合electron12开发后台管理系统项目.今天要分享的是最 ...
- go语言结构体内存对齐
cpu要想从内存读取数据,需要通过地址总线,把地址传输给内存,内存准备好数据,输出到数据总线,交给cpu,如果地址总线只有8根,那这个地址就只有8位可以表示[0,255]256个地址,因为表示不了更多 ...
- 『心善渊』Selenium3.0基础 — 8、使用CSS选择器定位元素
目录 1.CSS选择器介绍 2.CSS选择器定位语法 3.Selenium中使用CSS选择器定位元素 (1)通过属性定位元素 (2)通过标签定位元素 (3)通过层级关系定位元素 (4)通过索引定位元素 ...
- 快速简单的了解VLAN(VXLAN)和端口链路类型
目录 前言 一.VLAN是什么? 1.优点 2.为什么推出VXLAN 二.VXLAN又是什么? 1.优点 三.创建VLAN 四.介绍端口链路类型 五.Access 1.特性 六.Trunk 1.特性 ...
- 配置本地yum源以及挂载镜像
配置本地yum源以及挂载镜像(centos7.6) 配置yum源 # cd /etc/yum.repos.d 可以备份或者删除里面的文件 新建文件 # touch /etc/yum.repos.d/l ...