spring - Data JPA - Concurrent Testing - Stack Overflow

I just want to better understand the default behaviour of data jpa and postgressql regarding race condi

I just want to better understand the default behaviour of data jpa and postgressql regarding race conditions and ACID.

Therefore I create an Account Table and JPA Entity aswell as a Service that manages the account transfers from one user to another.

I first created a synchronous test to test the setup is correct. After that I created a concurrency test where I was expecting it to fail because I don't handle any race conditions and as far as I understand the default ACID behavior of Postgresql is READ COMMITED which only prevents dirty reads. But actually the test fails because it seems that only 1 transaction (deposit) has been registered. So in the end both accounts will have a balance of 50. I was expecting that more money has been created.

I setup an integration test using a docker container with the latest postgresql and Import the AccountService inside the test.

@Service
public class AccountService {
    @Autowired
    private AccountRepository accountRepository;

    @Transactional
    public void deposit(int from, int to, int amount) {
        Account f = accountRepository.findByOwner(from).orElseThrow(RuntimeException::new);
        Account t = accountRepository.findByOwner(to).orElseThrow(RuntimeException::new);
        if (f.getBalance() >= amount) {
            f.setBalance(f.getBalance() - amount);
            t.setBalance(t.getBalance() + amount);
            accountRepository.save(f);
            accountRepository.save(t);
        }
    }
}

@DataJpaTest
@Import(AccountService.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class ConcurrencyTest {
    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private AccountService accountService;


    @BeforeEach
    void setUp() {
        Account from = Account
                .builder()
                .owner(1)
                .balance(100)
                .build();

        Account to = Account
                .builder()
                .owner(2)
                .balance(0)
                .build();

        accountRepository.save(from);
        accountRepository.save(to);
    }

    @Test
    public void testSync() {
        accountService.deposit(1, 2, 50);

        
        Account f = accountRepository.findByOwner(1).get();
        Account t = accountRepository.findByOwner(2).get();
        assertEquals(50, f.getBalance());
        assertEquals(50, t.getBalance());
    }

    @Test
    public void concurrencyTest() throws InterruptedException {
        int NUMBER_OF_THREADS = 5;
        ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
        CountDownLatch countDownLatch = new CountDownLatch(NUMBER_OF_THREADS);
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            executorService.submit(() -> {
                try {
                accountService.deposit(1, 2, 50);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                finally {
                countDownLatch.countDown();
                }
            });
        }

        countDownLatch.await();
        executorService.shutdown();


        Account f = accountRepository.findByOwner(1).get();
        Account t = accountRepository.findByOwner(2).get();
        assertEquals(0, f.getBalance()); // result is 50
        assertEquals(100, t.getBalance()); // result is 50

    }

}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744709277a4589241.html

相关推荐

  • spring - Data JPA - Concurrent Testing - Stack Overflow

    I just want to better understand the default behaviour of data jpa and postgressql regarding race condi

    1天前
    40

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信