Spring Boot 2.7+下如何捕获getReferenceById的EntityNotFoundException
解决Spring Boot 2.7+中无法捕获EntityNotFoundException的问题
在Spring Boot 2.7及以上版本中,getOne()和getById()已被弃用,官方推荐使用getReferenceById(),但直接捕获javax.persistence.EntityNotFoundException往往失效,核心原因是:getReferenceById()返回的是Hibernate代理对象,此时并未执行数据库查询;只有当你访问代理对象的非ID属性时,才会触发SQL查询,若实体不存在才会抛出异常。如果异常抛出时机不在try块范围内,或者被Spring包装为其他异常(如org.springframework.dao.EmptyResultDataAccessException),自然无法被原代码的catch块捕获。
以下是几种无需降级版本的解决方案:
方案一:使用findById()(推荐)
findById()返回Optional类型,天然支持空值处理,无需捕获异常,代码更简洁安全:
fun getDonation(donationId: Long): DonationDto? { return donationJpaRepository.findById(donationId) .map(mapper::toDonationDto) .orElse(null) }
方案二:主动触发代理加载,捕获异常
如果坚持使用getReferenceById(),需在try块内主动访问实体属性触发数据库查询,同时考虑捕获Spring包装的异常:
fun getDonation(donationId: Long): DonationDto? { return try { val entity = donationJpaRepository.getReferenceById(donationId) // 主动触发加载,调用实体的任意非ID属性 entity.donationTime // 替换为你实体中的实际属性 mapper.toDonationDto(entity) } catch (e: EntityNotFoundException) { null } catch (e: org.springframework.dao.EmptyResultDataAccessException) { // 捕获Spring包装的实体不存在异常 null } }
方案三:全局异常处理(适用于接口层统一响应)
如果是在Web层处理,可以通过全局异常捕获处理EntityNotFoundException或其包装异常,统一返回空值或错误响应:
@ControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(value = [EntityNotFoundException::class, EmptyResultDataAccessException::class]) @ResponseBody fun handleEntityNotFound(): ResponseEntity<Any?> { return ResponseEntity.ok(null) } }
内容的提问来源于stack exchange,提问作者chujudzvin
相关产品推荐
相关产品推荐

