如何在运行在多个JVM上的spring应用程序中启用事务管理

时间:2019-02-26 14:43:48

标签: spring spring-batch spring-transactions distributed-transactions

最近几个月,我开始使用Spring框架。我对以下情况下的事务管理器的工作方式有疑问。

场景: 我正在处理Spring批处理,其中ItemReader多次调用以下方法。此方法从“学生”表中获取状态为“未完成”的记录列表,并将这些记录的状态更新为“进行中”。我正在处理1000万条记录,因此计划使用多个线程和多个JVM执行批处理。

目前已实施的解决方案: 我已使该方法同步化,以确保在给定的时间只有一个线程读取记录,以便没有两个线程会尝试获取相同的“未完成”记录。还添加了@Transactional,以便在此方法中发生任何问题时,spring都会回滚更改。

问题: 事务管理如何与多个JVM访问一个数据库一起工作?如果我正在运行2-3个应用程序实例,那么如何确保这些实例不尝试获取状态为“未完成”的相同记录?春天有这个功能吗?

@Transactional
public synchronized List<Student> processStudentRecords(){
List<Student> students = getNotCompletedRecords();
if(null != students && students.size() > 0){
    updateStatusToInProgress(students);
}
return student;
}

1 个答案:

答案 0 :(得分:0)

要专门解决您的问题:

  1. 请勿在Spring Batch使用的组件上使用@Transactional。 Spring Batch管理事务,使用该批注会引起问题。
  2. 要使用过程指示器标志(如您建议的那样),您需要在选择之前 进行更新。选择应该只查询已被标记的可用于处理的记录。

但是,以上内容未能解决多个JVM的问题。我假设您正在跨多个JVM的处理中使用某种远程分区。如果是这种情况,您的更新查询将类似于UPDATE STUDENTS SET FLAG = 'NOT COMPLETE' WHERE ID > ? AND FLAG IS NULL LIMIT 100,其中ID是分区范围的开始,而100是您的块大小。

标记完行后,ItemReader可以通过SELECT * FROM STUDENT WHERE ID > ? AND FLAG = 'NOT COMPLETE'之类的查询,其中ID是分区范围的开始。

以上技术可让您扩展到多个JVM,同时保留诸如可重新启动性之类的功能。