CrudRepository的deleteById方法仅生成select查询不执行删除如何解决
问题根因分析
Spring Data JPA 中 deleteById(ID id) 的默认执行流程如下:
- 调用
findById(id)查询对应实体,你看到的select语句就来自这个步骤 - 若查询结果为空,直接抛出
EmptyResultDataAccessException;若实体存在,才会调用delete(T entity)生成delete语句执行删除
没有生成delete语句,说明流程在第二步被中断,可按以下优先级排查:
排查与解决方案
- 验证待删除ID是否存在
你可以在delete操作前手动调用applicationRepo.existsById(applicationId)打印返回值,如果返回false,说明对应ID在application表中不存在,自然不会执行删除。 - 检查@Transactional注解生效状态
- 确认导入的是
org.springframework.transaction.annotation.Transactional,而非jakarta.transaction.Transactional,后者Spring默认不会识别 - 确认
deleteApplicationData方法是public,且是从类外部调用:如果是类内部的非事务方法直接调用本类的事务方法,会因为AOP代理规则导致事务失效 - 确认方法/类上的
@Transactional没有配置readOnly = true:只读事务会忽略所有写入操作,不会提交删除请求到数据库
- 确认导入的是
- 处理关联关系约束
你的Application实体中Reports字段配置了@OneToOne @PrimaryKeyJoinColumn,属于共享主键的一对一关联。如果Reports表中存在对应ID的记录,且关联的拥有方是Reports,没有配置级联删除的情况下,Hibernate会因为外键约束静默跳过删除操作,不会生成delete语句。
可选择两种解决方案:- 先删除关联的
Reports记录,再执行Application的删除 - 给
reports字段补充配置cascade = CascadeType.ALL, orphanRemoval = true,让删除Application时自动级联删除关联的Reports
- 先删除关联的
- 排查全局删除拦截规则
检查项目是否配置了全局软删除规则,比如使用@SQLDelete注解覆盖了默认删除逻辑、配置了JPA删除拦截器将物理删除改为更新删除标记字段的操作,这类配置都会导致不会生成delete语句。 - 确认事务未被回滚
检查deleteApplicationData方法执行过程中是否抛出未捕获的异常,异常会触发事务回滚,导致删除操作不会提交到数据库。
内容的提问来源于stack exchange,提问作者Bishal Dubey
相关产品推荐
相关产品推荐

