解决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 ...
随机推荐
- 如何在CentOS 7上搭建LAMP环境(使用YUM或编译)
什么是LAMP? LAMP是Linux,Apache,MySQL和PHP的缩写. 它是一堆应用程序的堆栈,它们在Web服务器上一起工作以托管网站. 话虽如此,每个程序都有不同的目的: 在LAMP中, ...
- 注册中心ZooKeeper,Eureka,Consul,Nacos对比
简介 服务注册中心本质上是为了解耦服务提供者和服务消费者.对于任何一个微服务,原则上都应存在或者支持多个提供者,这是由微服务的分布式属性决定的.更进一步,为了支持弹性扩缩容特性,一个微服务的提供者 ...
- Oracle11g RAC详解
升级变化: Oracle10g,高版本都是由低版本升级得到的.要装10.2.0.4,必须先安装database10.2.0.1,然后给这个ORACLE_HOME打补丁p6180189 ...
- WIN10无法进行Android应用开发真机调试解决方案
在WIN10操作系统进行ANDROID开发真机调试时,遇到的问题主要归纳一下有以下几点: 一.没有打开"USB调试"项.这点不再赘述: 二.没有安装ADB Interface驱动: ...
- UVA 10689 Yet another Number Sequence 矩阵快速幂 水呀水
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...
- 学习django的日子
bilibii这个网站是个学习者网站,里面有很多学习视频
- 获取 Windows 密码「GitHub 热点速览 v.21.28」
作者:HelloGitHub-小鱼干 安全问题一直是 GitHub 的一大热点,因为数据安全问题诞生的各类自托管服务便是.而本周周榜上的 2 个和安全主题相关的项目,有些不同.mimikatz 是个老 ...
- Java:Java中static关键字作用
static关键字最基本的用法是: 1.被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来 2.被static修饰的方法属于类方法,可以通过类名.方法名直接引用 ...
- 确保 PHP 应用程序的安全 -- 不能违反的四条安全规则(转)
规则 1:绝不要信任外部数据或输入 关于 Web 应用程序安全性,必须认识到的第一件事是不应该信任外部数据.外部数据(outside data) 包括不是由程序员在 PHP 代码中直接输入的任何数 ...
- MindInsight:一款基于MindSpore框架的训练可视化插件
技术背景 在深度学习或者其他参数优化领域中,对于结果的可视化以及中间网络结构的可视化,也是一个非常重要的工作.一个好的可视化工具,可以更加直观的展示计算结果,可以帮助人们更快的发掘大量的数据中最有用的 ...