首页 > 解决方案 > 在具有更新值的事务中保存相同的实例两次

问题描述

我正在 Spring Boot 中编写多线程 cron 作业。我有一个需要对其执行某些操作的用户列表。以下是 cron 作业的片段

public void executeCronJob() {
    LOG.debug("Started >>>");
    User user = userService.findFirstNotInProgress();
    if (user == null) {
        LOG.debug("<<< User not found");
        return;
    }
    userService.updateStatus(user, Status.IN_PROGRESS);
    someOtherService.doSomeActionRelatedToUser(user);
    userService.updateStatus(user, Status.COMPLETED);
    LOG.debug("<<< Completed");
}

UserService.java中

private void updateStatus(User user, Status status) {
    user.setStatus(status);
    userRepository.save(user);
}

我正在使用多线程,因为该someOtherService.doSomeActionRelatedToUser(user);方法可能需要相当长的时间,因此会阻止其他用户的执行。第一次调用userService.updateStatus工作正常,用户进入IN_PROGRESS状态。但是在执行someOtherService与用户相关的操作后,当我userService.updateStatus再次调用以将状态设置为COMPLETED时,出现错误

行被另一个事务更新或删除(或未保存值映射不正确)

我曾尝试userRepository.saveAndFlush(user);在 UserService 中使用,但它仍然给我同样的错误。我该如何解决这个问题?

标签: javamultithreadingspring-bootcrontransactions

解决方案


您正在将user与会话相关联的传递给多个线程,并且由于 Hibernate Session 对象不是线程安全的,因此您最终会遇到此错误。

doSomeActionRelatedToUser()您可以使用新会话而不是 from将状态更新为 COMPLETED executeCronJob()

或者您可能想要someOtherService.doSomeActionRelatedToUser(user);返回CompletableFuture然后更新状态。

希望能帮助到你。


推荐阅读