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

异步批量删除用户活动实体触发EmptyResultDataAccessException问题排查

问题原因及解决方案

出现这种尝试删除不存在实体的情况,核心原因是查询ID和删除操作不是原子性的,中间存在时间窗口导致数据发生变化,具体可能的场景:

  • 并发任务冲突:如果这个异步调度任务被同时触发多个实例,或者有其他业务逻辑也在删除UserActivity实体,就会出现:A实例查询到ID461,在A执行删除前,B实例已经把这个ID的实体删掉了,等A去删的时候自然找不到。
  • 事务间隙:查询操作和删除操作分属两次数据库交互,哪怕是同一个事务,也可能因为其他已提交的事务在这两个操作之间删除了目标实体。

针对你的代码,有几种优化方式可以避免这个问题:

  1. 直接批量删除,跳过查询ID的步骤
    不用先查ID再循环删除,直接在Repository里定义批量删除方法,比如:

    @Modifying
    @Transactional
    void deleteByCreatedBefore(LocalDateTime createdBefore);
    

    这样数据库层面直接执行删除逻辑,是原子操作,不会出现查删不一致的情况。

  2. 删除前先检查实体是否存在
    如果必须保留循环删除的逻辑,可以在deleteById前先判断实体是否存在:

    if(userActivityRepository.existsById(uaId)) {
        userActivityRepository.deleteById(uaId);
    }
    

    不过要注意,exists和delete依然不是原子的,极端并发下还是可能出现问题,但能减少报错概率。

  3. 捕获特定异常并忽略
    既然你已经捕获了Exception,也可以针对性捕获EmptyResultDataAccessException,然后只打日志不做额外处理,因为这种情况本质是数据已经被删了,不需要再执行操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:08:16