jpa在save失败后service端catch不到异常原因(Hibernate的一级缓存)
Posted 好大的月亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jpa在save失败后service端catch不到异常原因(Hibernate的一级缓存)相关的知识,希望对你有一定的参考价值。
现象
jpa
在save
失败后service
端catch
不到异常原因。
jpa
的save
是先保存到缓存的,没有立即插入到数据库,在提交事务时,才会尝试刷新缓存中的数据到数据库。
或者手动调用flush
方法,强制把数据刷到数据库。
Hibernate缓存包括两大类:一级缓存和二级缓存。
一级缓存又称为“Session的缓存”,它是内置的,不能被卸载(不能被卸载的意思就是这种缓存不具有可选性,必须有的功能,不可以取消session缓存)。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存在第一级缓存中,持久化类的每个实例都具有唯一的OID。我们使用@Transactional 注解时,JpaTransactionManager会在开启事务前打开一个session,将事务绑定在这个session上,事务结束session关闭,所以后续内容将以粗略以事务作为一级缓存的生存时段。
二级缓存又称为“SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略。
第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件,二级缓存应用场景局限性比较大,适用于数据要求的实时性和准确性不高、变动很少的情况。
一般不会开启二级缓存,会引入诸如并发方面的问题
save方法流程
我们使用CrudRepository.save
方法保存或更新对象的流程如下:
其中如果entity
实体设置了自增主键,就只会打印出一条insert
语句.即直接插入。
而如果entity
只是设置了主键,未设置增长策略,在调用save
方法时,就会先打出一条select
语句,再打出一条insert
语句。如果加了事务,调用save
方法时,会出现save
失败后service
端catch
不到异常的现象,因为先保存到了一级缓存,等这个方法结束后提交事务才会将数据刷到数据库,这个时候数据库那边报错了,这个异常就会返回到调用这个方法的层级。
综上分析
如果实体类使用自增主键,无论是否加事务,都先将缓存中的数据插入数据库,再执行业务操作,可以正常触发try-catch
的异常捕获。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
不设置主键的自增策略,加事务,会先将数据保存在缓存,然后执行余下的业务逻辑,然后再将缓存中的数据刷新到数据库中,在刷数据到库时发生异常,但由于此时业务逻辑已经执行完,无法触发try-catch
的异常捕获机制。
以上是关于jpa在save失败后service端catch不到异常原因(Hibernate的一级缓存)的主要内容,如果未能解决你的问题,请参考以下文章
centos 7 中没有iptables 和service iptables save 指令使用失败问题解决方案
SpringBoot JPA 在@Transactional 上不需要 .save() 吗? [复制]
spring spring data jpa save操作事务