You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA delete未执行:调用删除后立即抛异常无法删除数据库数据

问题根本原因

你的问题核心是Spring事务默认的回滚机制导致的:

  • 你当前的verifyExpiration方法必然处于一个开启的事务中(不管是方法自身加了@Transactional,还是上层调用方开启的事务把该方法逻辑纳入)
  • Spring声明式事务默认会在方法抛出RuntimeException(未检查异常)或Error时触发全事务回滚
  • 你的删除操作和后续抛出TokenException的逻辑处于同一个事务中,异常抛出后整个事务回滚,之前的删除操作自然不会生效
  • JPA的持久化上下文默认是事务提交时才会将变更刷入数据库,在事务回滚的情况下,内存中的删除操作根本不会同步到数据库
解决方案

以下是几种常用的修复方案,可根据你的业务场景选择:

  1. 将删除逻辑放到独立的新事务中(最推荐)
    给delete方法加上独立事务的注解:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void delete(String token) {
    this.refreshTokenRepository.deleteByToken(token);
}

注意:不可在同类中直接调用加了REQUIRES_NEW的方法,否则事务注解不生效,需要将delete方法抽到独立的Bean中,或者通过AOP代理对象调用该方法。

  1. 调整当前事务的回滚规则
    给外层方法加上注解,指定遇到TokenException时不回滚,同时删除后手动刷入数据库:
@Transactional(noRollbackFor = TokenException.class)
public void verifyExpiration(RefreshToken token) {
    if (token.getExpiryDate().compareTo(Instant.now()) < 0) {
        this.refreshTokenRepository.deleteByToken(token);
        this.refreshTokenRepository.flush(); // 手动将删除操作刷入数据库
        throw new TokenException("Refresh token was expired: " + token.getToken());
    }
}

注意:该方案会让整个方法的所有操作在遇到TokenException时都不回滚,如果方法内还有其他写操作需要回滚,不要使用该方案。

  1. 调整业务逻辑触发时机
    在上层调用verifyExpiration方法的位置捕获TokenException,捕获成功后再执行删除操作,避免删除和异常在同一个事务中。

内容的提问来源于stack exchange,提问作者256

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:36:03