【问题标题】:Spring: Not able to write to Autowired repository when using TimerTaskSpring:使用 TimerTask 时无法写入 Autowired 存储库
【发布时间】:2018-05-09 14:22:50
【问题描述】:

我有一个方法可以定期更新数据库中的记录。

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    private Boolean flag = false;

    @Transactional
    public int method1(Args args) {
        //  do something
        if (!flag) {
            method2()
        }
        return x;
    }

    @Transactional
    public int method2(Args args) {
        polling = true;
        Timer t = new Timer();
        t.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                List<Records> records = myRepository.getRecords()

                for (Record record : records ) {

                    // prints the Id of each record. Now, they are all have Id=1
                    System.out.println(record.getId());

                    // setting the record's Id to 5
                    record.setId(5);

                    // prints '5'
                    System.out.println(record.getId());
               }

            }
        }, 10, 1000*60*4
    }
}

Method1 调用 Method2。 Method2 每 4 分钟执行一次 run() 函数内的代码。 run() 中的代码无需调度即可正常工作(获取每条记录的 Id,打印它们,通过将 Id 设置为 5 来更新数据库)。 然而,现在,随着我使用 TimerTask,它仍然检索并打印 Id,据说将每条记录的 Id 设置为 5,甚至在 record.get(Id) 处打印出“5”,这让我相信数据库是成功的使用新 ID 更新。 当我实际检查我的数据库时,我发现 Ids 实际上没有更新到 5。原始 Ids 仍然存在。 我不确定为什么会发生这种情况,因为似乎 ID 正在更新。这与 TimerTask 创建新线程有关吗?

【问题讨论】:

  • 您正在从 inside 方法中分离出TimerTask,但您的任务方法本身并不是事务性的。请改用@Scheduled
  • 使用@Scheduled 并让它工作。谢谢!

标签: java spring spring-mvc scheduled-tasks timertask


【解决方案1】:

@Transational 假设它将针对 DB 包装一个 TRANSACTION,因此您需要让您的 @Transactional 函数在它们做一件事的地方,让它们立即退出。您知道数据库将已提交或回滚。根据事务隔离级别(您可能想要研究的另一个主题,但可能不需要),在该函数实际返回之前,@Transactional 内部发生的问题永远不会被写入 db。这可能就是你所缺少的。 Chrylis 使用@Scheduled 来“重复事物”是正确的,但真正的问题是我所说的那个,对他/她应有的尊重。

总结:让你的@Scheduled 函数调用一个@Transactional 函数(对于你想要做的每个数据库事务),然后它就会工作。

【讨论】: