如何在使用spring提交更新后锁定选择和释放锁定?

问题描述 投票:0回答:1

我已经开始使用过去几个月的春天了,我对交易有疑问。我在我的spring批处理作业中有一个java方法,它首先执行select操作以获得状态为“NOT COMPLETED”的前100行,并对所选行进行更新以将状态更改为“IN PROGRESS”。由于我正在处理大约1000万条记录,我想运行我的批处理作业的多个实例,每个实例都有多个线程。对于单个实例,为了确保两个线程没有获取同一组记录,我将我的方法设为同步。但是如果我运行我的批处理作业的多个实例(多个JVM),即使我使用“乐观”或“pesimistic锁”或“选择更新”,很可能两个实例都可以获取同一组记录。我们无法在选择期间锁定记录。以下是显示的示例。事务1已经获取了100条记录,同时Transaction2也获取了100条记录但是如果我启用了锁定事务2,则等待事务1更新并提交。但是,Transaction 2再次进行相同的更新。

在春天有没有办法让事务2的选择操作等到事务1的选择完成?

Transaction1        Transaction2
fetch 100 records   
                    fetch 100 records
update 100 records



 commit         
                    update 100 records
                    commit



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

注意:我无法先执行更新然后选择。如果建议采用其他方法,我将不胜感激?

spring spring-batch spring-transactions optimistic-locking pessimistic-locking
1个回答
0
投票

事务同步应留给数据库服务器,而不是在应用程序级别进行管理。从数据库服务器的角度来看,无论您拥有多少个JVM(线程),这些都是要求读/写操作的并发数据库客户端。你不应该为这些担忧而烦恼。

你应该做的是尝试尽可能减少解决方案设计中的争用,例如,使用(remote) partitioning technique

如果我运行我的批处理作业的多个实例(多个JVM),即使我使用“乐观”或“pesimistic锁”或“选择更新”,很可能两个实例都可以获取同一组记录,因为我们选择期间无法锁定记录

分区数据将通过设计消除所有这些问题。如果为每个实例提供一组要处理的数据,则工作人员不可能选择另一个工作人员的相同记录。迈克尔在这个答案中给出了一个详细的例子:https://stackoverflow.com/a/54889092/5019386

(逻辑)然而,分区不会解决争用问题,因为所有工作人员都会读/写同一个表,但这就是您要解决的问题的本质。我所说的是你不需要在你的设计中开始锁定/解锁表格,把它留给数据库。像Oracle这样的一些数据库服务器可以将同一个表的数据写入磁盘上的不同分区,以优化并发访问(如果使用分区可能会有所帮助),但这也是Oracle的业务,而不是Spring(或任何其他框架)业务。

不是每个人都能买得起甲骨文,所以我会在概念层面寻找解决方案。我已成功使用以下解决方案(“伪”物理分区)来解决与您类似的问题:

  • 步骤1(串行):将未处理的数据复制/分区到临时表(串行)
  • 步骤2(并行):在这些表上运行多个worker而不是具有数百万行的源表。
  • 步骤3(串行):将处理后的数据复制/更新回原始表

第2步消除了争用问题。通常,与步骤2相比,(步骤1 +步骤3)的成本是可忽略的(如果步骤2是串行完成则更加忽略)。如果处理是瓶颈,这很有效。

希望这可以帮助。

© www.soinside.com 2019 - 2024. All rights reserved.