使用同步时在Spring分区中出现意外情况

使用同步时在Spring分区中出现意外情况,spring,hibernate,spring-boot,spring-data-jpa,spring-batch,Spring,Hibernate,Spring Boot,Spring Data Jpa,Spring Batch,我使用Spring批处理和分区来进行并行处理。Hibernate和Spring数据Jpa for db。对于分区步骤,读取器、处理器和写入器都有stepscope,因此我可以向它们注入分区键和范围(从到)。现在在processor中,我有一个同步的方法,并希望这个方法一次运行一次,但事实并非如此 我将它设置为有10个分区,所有10个项目读取器都读取了正确的分区范围。问题来自项目处理器。Blow代码与我使用的逻辑相同 public class accountProcessor implemente

我使用Spring批处理和分区来进行并行处理。Hibernate和Spring数据Jpa for db。对于分区步骤,读取器、处理器和写入器都有stepscope,因此我可以向它们注入分区键和范围(从到)。现在在processor中,我有一个同步的方法,并希望这个方法一次运行一次,但事实并非如此

我将它设置为有10个分区,所有10个项目读取器都读取了正确的分区范围。问题来自项目处理器。Blow代码与我使用的逻辑相同

public class accountProcessor implementes ItemProcessor{
    @override
    public Custom process(item) {
        createAccount(item);
        return item;
    }

    //account has unique constraints username, gender, and email
    /*
        When 1 thread execute that method, it will create 1 account 
        and save it. If next thread comes in and  try to save the  same  account, 
        it  should find the account created by first thread and do one update. 
        But now it doesn't happen, instead findIfExist return null 
        and it  try to do another insert of duplicate data
    */
    private synchronized void createAccount(item) {
        Account account = accountRepo.findIfExist(item.getUsername(),  item.getGender(),  item.getEmail());
        if(account  == null) {
            //account  doesn't  exist
            account = new Account();
            account.setUsername(item.getUsername());
            account.setGender(item.getGender());
            account.setEmail(item.getEmail());
            account.setMoney(10000);
        } else {
            account.setMoney(account.getMoney()-10);
        }
        accountRepo.save(account);
    }
}
预期的结果是,在任何给定的时间,只有1个线程将运行此方法,这样在db中就不会有重复的插入,并避免DataintegrityViolationexception

实际上,结果是第二个线程找不到第一个帐户,并尝试创建一个重复的帐户并保存到db,这将导致DataintegrityViolationexception,unique constraints错误

因为我同步了这个方法,所以线程应该按顺序执行它,第二个线程应该等待第一个线程完成,然后运行,这意味着它应该能够找到第一个帐户

我尝试了很多方法,比如使用volatile设置来包含所有唯一的帐户,使用saveAndFlush尽快提交,使用threadlocal,这些方法都不管用


需要一些帮助。

由于您对项目处理器步骤的作用域进行了限定,因此实际上不需要同步,因为每个步骤都有自己的处理器实例

但看起来您遇到的是设计问题,而不是实现问题。您正在尝试同步线程,以便在并行设置中按特定顺序执行操作。当您决定并行并将数据划分为分区,并为每个工作人员(本地或远程)提供一个分区来处理时,您必须承认这些分区将按未定义的顺序进行处理,并且每个分区的记录之间或每个工作人员所做的工作之间不应有任何关系

当一个线程执行该方法时,它将创建一个帐户 并保存它。如果下一个线程进入并尝试保存同一个帐户, 它应该找到由第一个线程创建的帐户并执行一次更新。但现在它没有发生,而是findIfExist返回null,并尝试再次插入重复数据

这是因为thread1的事务可能尚未提交,因此thread2将找不到您认为由thread1插入的记录

看起来您正在尝试使用分区设置创建或更新某些帐户。我不确定此设置是否适合当前的问题

作为旁注,我不会调用
accountRepo.save(account)


希望这能有所帮助。

如果您的处理器是step scope,则将有10个processor@PrabhakarD您的意思是,对于这10个处理器,每个处理器都有自己的同步方法?即使在写入步骤中,任何同步方法的行为都是相同的!thread1的事务可能未提交,thread2进行读取!为实现此实现,是否有其他建议的设计实现?