Объект, извлеченный с блокировкой pessimisti c, имеет устаревшее значение - PullRequest
0 голосов
/ 07 апреля 2020

я тестирую какой-то небольшой банковский сервис i-1019 * с базой данных mysql.

я использую спящий режим кэша 2-го уровня (возможный источник проблемы?).

структура данных в основном состоит из 2 таблиц, таблицы для списка транзакций (депозитов) и таблицы для хранения последнего остатка для каждой учетной записи, которая должна обновляться одновременно.

и пока я тестирую параллелизм, я вижу некоторые ошибки в моей программе. вот мой код, он не идеален, но на самом деле работает.

@Service
@Transactional
public class depositService {

    //method below is being executed concurrently
    public Deposit save(Long userId, BigDecimal amount){ //add deposit transaction into transaction list and update related user balance

        DepositTransaction depositTransaction = new DepositTransaction();
        depositTransaction.setUserId(userId);
        depositTransaction.setAmount(amount);
        DepositTransaction depositTransactionLatest = depositTransactionRepository.findTopWithLockByUser_IdOrderByIdDesc(userId).orElse(new DepositTransaction());
depositTransaction.setBalance(depositTransactionLatest.getBalance().add(depositTransaction.getAmount())); // balance increment works well 
        depositTransaction = depositTransactionRepository.save(depositTransaction); //add into transaction table works as expected without any inconsistencies / lost update

        AccountBalance accountBalance = accountBalanceRepository.findOneWithLockById(depositTransaction.getUserId()).orElse(null); //update user balance
        accountBalance.setBalance(accountBalance.getBalance().add(depositTransaction.getAmount())); //most of the time, accountBalance.getBalance still having outdated value
        accountBalanceRepository.save(companyBank);
    }
}
@Repository
public interface DepositTransactionRepository{
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    Optional<DepositTransaction> findTopWithLockByUser_IdOrderByIdDesc(Long userId);
}
@Repository
public interface AccountBalanceRepository{
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    Optional<AccountBalanceTransaction> findOneWithLockById(Long userId);
}

на основе приведенного выше кода, у меня есть транзакция, и внутри нее я использую 2 pessimisti c блокировки выборки для 2 лица. сгенерированные запросы содержат «для обновления» правильно и заблокированы должным образом, так как я пытался получить блокировку, и мне не удалось использовать mysql командную строку.

моя проблема заключается в том, что при наличии одновременного запроса баланс счета будет иметь несоответствия, но я не совсем понимаю, почему блокировка депозитной транзакции может это сделать.

accountBalance.getBalance () всегда будет иметь устаревшее значение и ему придется ждать несколько итераций, чтобы изменить его на обновленное значение.

Я могу сделать эту работу, если я использую сериализованную изоляцию транзакции с механизмом повтора в случае тупика. но я предпочитаю пессимисты c, если это возможно.

...