早上好,
我正在尝试创建一个计划任务,该任务必须周期性地更新数据库实体,我使用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)
。
在我看来,这显然是可行的,因为不需要可伸缩性,因此序列化操作不会给应用程序带来任何问题。