복붙노트

[SPRING] 동기화를 사용할 때 Spring 파티션에서 예기치 않은 오류가 발생했습니다.

SPRING

동기화를 사용할 때 Spring 파티션에서 예기치 않은 오류가 발생했습니다.

Spring Batch와 Partition을 사용하여 병렬 처리합니다. DB에 대한 최대 절전 모드 및 스프링 데이터 Jpa. 파티션 단계의 경우 판독기, 프로세서 및 작성기에 stepscope이 있으므로 파티션 키와 범위 (from-to)를 주입 할 수 있습니다. 이제 프로세서에서 하나의 동기화 된 메서드가 있으며이 메서드를 한 번 실행하면되지만이 경우는 아닙니다.

나는 10 개의 파티션을 갖도록 설정했는데, 모두 10 개의 아이템 리더가 올바른 파티션 된 범위를 읽었습니다. 문제는 항목 프로세서와 함께 제공됩니다. 블로우 코드는 내가 사용하는 로직과 같습니다.

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);
    }
}

예상되는 결과는 주어진 시간에 오직 하나의 쓰레드 만이 메소드를 실행하므로 DataintegrityViolationexception을 피할뿐만 아니라 db에 중복 된 inserttion이 존재하지 않는다는 것입니다.

실제로 결과는 두 번째 스레드가 첫 번째 계정을 찾을 수 없으며 DataintegrityViolationException, 고유 제약 조건 오류를 일으킬 중복 계정을 만들고 db에 저장하려고합니다.

메소드를 동기화했기 때문에 스레드는 순서대로 실행해야하고 두 번째 스레드는 첫 번째 스레드가 완료되고 실행될 때까지 기다려야하므로 첫 번째 계정을 찾을 수 있어야합니다.

나는 모든 접근법을 시도했다. 휘발성 셋트는 모든 고유 한 계정을 포함하고 saveAndFlush는 가능한 한 커밋을 만들어 스레드 로칼을 사용한다.

도움이 필요해.

해결법

  1. ==============================

    1.아이템 프로세서를 단계별로 설정 했으므로 각 단계마다 프로세서의 자체 인스턴스가 있으므로 실제로 동기화 할 필요가 없습니다.

    아이템 프로세서를 단계별로 설정 했으므로 각 단계마다 프로세서의 자체 인스턴스가 있으므로 실제로 동기화 할 필요가 없습니다.

    하지만 구현 문제보다는 디자인 문제가있는 것처럼 보입니다. 병렬 설정에서 특정 순서로 스레드가 동기화되도록하려고합니다. 병렬로 가고 데이터를 파티션으로 나누고 각 작업자 (로컬 또는 원격)에게 작업 할 파티션을 제공하려면 이러한 파티션이 정의되지 않은 순서로 처리되고 레코드 간에는 관계가 없어야 함을 인정해야합니다 또는 각 작업자가 수행 한 작업간에

    왜냐하면 thread1의 트랜잭션이 아직 커밋되지 않았기 때문입니다. 따라서 thread2는 thread1이 삽입했다고 생각하는 레코드를 찾지 않습니다.

    분할 된 설정으로 일부 계정을 만들거나 업데이트하려고하는 것 같습니다. 이 설정이 현재의 문제에 적합한 지 여부는 확실하지 않습니다.

    부수적으로, 나는 accountRepo.save (account)를 호출하지 않을 것이다; 항목 처리기에서 처리하지만 오히려 항목 작성기에서 처리합니다.

    희망이 도움이됩니다.

  2. from https://stackoverflow.com/questions/54660694/unexpected-in-spring-partition-when-using-synchronized by cc-by-sa and MIT license