0

I'm trying to lock an jpa entity while i work with it, so it cannot be read/writen during this method invocation. But my testing shows the lock is not working righ Using spring-boot-starter-data-jpa, hibernate and postgresql.

This is the method:

public BalanceJournal addCreditsBankDeposit(
    Long licenseId, 
    String userId, 
    Integer credits) {
    return addCredits(
        BalanceJournalType.BANK_DEPOSIT, 
        licenseId, 
        userId,
        credits
    );
}

@Transactional(isolation = Isolation.SERIALIZABLE)
protected BalanceJournal addCredits(
    BalanceJournalType type, 
        Long licenseId, 
        String userId, 
        Integer credits) {
    //While this method running i need this license entity not to be readable
    License license = licenseRepo.findById(licenseId);

    BalanceJournal journal = balanceJournalRepo.save(new BalanceJournal()
        .withBalance(license.getBalanceTotal() + credits)
        .withCredit(credits)
        .withDebit(0)
        .withEntryTs(LocalDateTime.now())
        .withEntryType(type)
        .withsLicense(licenseId)
        .withLicenseUser(userId));
    licenseRepo.save(license.withBalanceTotal(journal.getBalance()));

    //when this method returns or throws exception, the license should be readable again.
    return journal;
}

My Repo classes are just JpaRepositories from Spring-Data

public interface BalanceJournalRepository extends JpaRepository<BalanceJournal, Long> {
}

I'm testing this out like this

final ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 1; i <= 5; i++) {
    final int amount = i;
    executor.execute(() -> balanceJournalService.addCreditsBankDeposit(licenseId, userId, amount));    
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

Before starting the test my license.balance = 0, and i have no journals. At the end i would expect to have my licence.balance = 15 (1+2+3+4+5) and 5 journals like:

1) credit=1, balance=1
2) credit=2, balance=3
3) credit=3, balance=6
4) credit=4, balance=10
5) credit=5, balance=15

But i end up with license.balance = 5

1) credit=1, balance=1
2) credit=2, balance=2
3) credit=3, balance=3
4) credit=4, balance=4
5) credit=5, balance=5

¿How can i acomplish the expected result?

liloargana
  • 165
  • 1
  • 10
  • What call chain from `addCreditsBankDeposit` to `addCredits`? If `@Transactional` method call from the same class this wouldn't work. – Grigorii Riabov Apr 29 '21 at 05:46
  • public BalanceJournal addCreditsBankDeposit(Long licenseId, String userId, Integer credits) { addCredits(BalanceJournalType.BANK_DEPOSIT, licenseId, userId, credits); } – liloargana Apr 30 '21 at 06:45
  • 1
    Does `addCreditsBankDeposit()` and `addCredits()` place in same class, and `addCreditsBankDeposit()` not marked by `@Transactional`? – Grigorii Riabov Apr 30 '21 at 06:51
  • Yes, just edited to question to include that method, just how i have it. – liloargana Apr 30 '21 at 06:56
  • 1
    And here is the problem, why `@Transactional` not works, [here](https://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo) answer why it not work. – Grigorii Riabov Apr 30 '21 at 07:03
  • RESOLVED, thanks @GrigoriiRiabov would had never figured that out, – liloargana Apr 30 '21 at 20:40

0 Answers0