Spring Boot 3.4(含Hibernate 6.6)后PessimisticLockingFailureException不再抛出
Spring Boot 3.4升级后悲观锁findById方法不抛出PessimisticLockingFailureException问题
问题现象
将Spring Boot升级至3.4版本(集成Hibernate 6.6)后,自定义CrudRepository中重写的带悲观锁的findById方法出现行为变更:
重写方法代码:
@Override @Lock(LockModeType.PESSIMISTIC_WRITE) @Nonnull Optional<DossierDb> findById(@Nonnull UUID id);
仓库定义:
@Repository public interface DossierDbRepository extends CrudRepository<DossierDb, UUID>
在带重试机制的测试场景中,该方法不再抛出PessimisticLockingFailureException。虽然日志仍会输出ERROR: current transaction is aborted, commands ignored until end of transaction block,但方法最终返回Optional.empty;而在Spring Boot 3.3版本中,会同时输出该日志并抛出异常。
已查阅Spring Data JPA发布记录、Spring Boot 3.4发布说明以及Hibernate 6.5、6.6迁移指南,均未找到该行为变更的明确说明,推测是Hibernate内部逻辑变更导致。
已尝试的方案及结果
- 添加
@Query注解:为findById方法手动添加@Query("select d from DossierDb d where d.id = :id")注解后,方法会抛出JpaSystemException: JDBC exception executing SQL [select {list of dossierDb columns} where id= for no key update][ERROR: current transaction is aborted, commands ignored until end of transaction block],该异常可正常触发重试机制。 - 调整
@Transactional注解配置:无论是将@Transactional(noRollbackFor = PessimisticLockException.class)添加到findById方法,还是修改现有带isolation = Isolation.REPEATABLE_READ的@Transactional注解增加noRollbackFor配置,均未对日志输出或异常抛出行为产生任何影响。
解决方案建议
目前添加自定义@Query注解是可行的临时方案,可让异常正常抛出并触发重试逻辑。若要进一步定位根因,可从以下方向排查:
- 跟踪Hibernate 6.6中悲观锁查询的执行流程,确认锁获取失败时的异常处理策略是否有变更;
- 对比Spring Data JPA 3.4与3.3版本中
CrudRepository.findById方法的实现差异,检查是否存在异常转换逻辑的调整; - 开启Hibernate DEBUG级别的日志,详细查看锁获取失败时的内部处理步骤,定位异常被吞掉的具体环节。
内容的提问来源于stack exchange,提问作者Jonathan Simonney
相关产品推荐
相关产品推荐

