早上好,

我正在尝试创建一个计划任务,该任务必须周期性地更新数据库实体,我使用Spring MVC和Hibernate作为ORM。

问题

计划的任务应在后台更新实体,但更改不会持久保存在数据库中。

系统结构

我有一个具有基本信息的Batch实体,并且每隔几秒钟就会有很多传感器在数据库中插入记录。

Batch实体相关,有一个TrackedBatch实体,其中包含许多与Batch实体本身相关的计算字段,计划任务逐个获取每个Batch,使用lotto = lottoService.updateBatchRelations(batch)更新来自传感器的相关数据然后使用新的计算数据更新TrackedBatch实体。

用户可以修改Batch基本信息,然后系统应重新计算TrackedBatch数据并更新实体(这由调用updateBatchFollowingModification方法的控制器完成)。此步骤已使用异步方法正确完成,当计划的任务应重新计算相同的信息时会出现问题。

用户修改后用于更新实体的Asynch方法(正常工作)

@Async("threadPoolTaskExecutor")
@Transactional
public void updateBatchFollowingModification(Lotto lotto)
{
    logger.debug("Daemon started");
    Lotto batch = lottoService.findBatchById(lotto.getId_lotto(), false);
    lotto = lottoService.updateBatchRelations(batch);
    lotto.setTrackedBatch(trackableBatchService.modifyTrackedBatch(batch.getTrackedBatch(), batch));
    logger.debug("Daemon ended");
}


定期更新实体的预定方法(无法按预期工作)

@Scheduled(fixedDelay = 10000)
public void updateActiveBatchesWithDaemon()
{
    logger.info("updating active batches in background");

    List<Integer> idsOfActiveBatches = lottoService.findIdsOfActiveBatchesInAllSectors();
    if(!idsOfActiveBatches.isEmpty())
    {
        logger.info("found " + idsOfActiveBatches.size() + " active batches");
        for(Integer id : idsOfActiveBatches)
        {
            logger.debug("update batch " + id + " in background");
            updateBatch(id);
        }
    }
    else
    {
        logger.info("no active batches found");
    }
}

@Transactional
public void updateBatch(Integer id)
{
    Lotto activeLotto = lottoService.findBatchById(id, false);
    updateBatchFollowingModification(activeLotto);
}


作为前提,我可以声明已调度的方法已正确触发/配置并且可以连续运行(该方法代表异步方法,因为在用户修改之后,所有实体均已正确更新),位于updateBatchFollowingModification(activeLotto)方法中的第updateBatch行,相关实体已正确修改(即使是TrackedBatch,我已经用调试器检查过),但是当方法结束并且没有引发异常时,更改不会持久保存在数据库中。

环顾互联网,我没有找到解决此问题的任何方法,也似乎不是Hibernate和Spring的已知问题或错误。

另外,阅读有关调度的Spring文档也无济于事,我还尝试在调度的任务中使用save方法来再次保存实体(但是很遗憾,它不起作用)。

进一步的考虑

我不知道@Scheduled批注是否需要一些额外的配置来处理@Transactional方法,因为在Web开发人员中使用这些批注没有问题,而且在文档中没有提及缺点。

我也不认为这是一个并发问题,因为如果异步方法正在修改数据,则计划的应由隐式乐观锁定系统停止,以便在第一个事务提交后完成,如果第一个事务提交则保持不变获取锁定是计划的方法(如果我错了,请纠正我)。

我无法弄清楚为什么使用计划的方法时更改不会持久化,有人可以链接有关此主题的文档或教程吗?因此我可以找到一个解决方案,或者更好的是,如果有人遇到类似的问题,该如何解决?

最佳答案

最终,我通过明确定义流程中涉及的事务的隔离级别并消除了updateBatch方法(因为它是与updateBatchFollowingModification相同的功能,是一种重复的功能),从而设法解决了该问题。我将updateBatchFollowingModification的隔离级别设置为@Transactional(isolation = Isolation.SERIALIZABLE)

在我看来,这显然是可行的,因为不需要可伸缩性,因此序列化操作不会给应用程序带来任何问题。

10-08 04:52