Весна JPA.Правильный способ обновления значений базы данных - PullRequest
0 голосов
/ 26 сентября 2018

Я изучаю Spring JPA и Hibernate.Итак, я столкнулся с проблемой.

У меня есть этот метод

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void sendMoney(Long from, Long to, Double amount) {
    WalletEntity fromWallet = walletServiceImpl.getWallet(from);
    WalletEntity toWallet = walletServiceImpl.getWallet(to);
    fromWallet.setAmount(fromWallet.getAmount() - amount);
    toWallet.setAmount(toWallet.getAmount() + amount);

    TransactionEntity transaction = new TransactionEntity();
    transaction.setAmount(amount);
    transaction.setToWallet(toWallet);
    transaction.setFromWallet(fromWallet);

    transactionRepository.saveAndFlush(transaction);
}

Я хотел проверить его и создал это:

@GetMapping("/send")
public void sendMoney() {
    ExecutorService executorService = Executors.newFixedThreadPool(20);
    for (int i = 0; i < 100; i++) {
        executorService.execute(() -> {
            accountServiceImpl.sendMoney(1L, 2L, 10D);
        });
    }
}

Поэтому, когда я читаю кошелек, яполучить старое значение, но я сделал Isolation.REPEATABLE_READ.Значения в базе данных неверны, конечно.Можете ли вы объяснить, что не так?Спасибо!

1 Ответ

0 голосов
/ 26 сентября 2018

Уровень изоляции REPTEABLE_READ работает по назначению.

Хорошее объяснение можно получить здесь:

Spring @Transactional - изоляция, распространение

Но чтобы уточнить, вот что происходит:

                      Tx1      Tx2
                       |        |
Tx1 Read Wallet 1     100       |
Tx2 Read Wallet 1      |       100
Tx1 Discounts 10     100-10     |
Tx2 Discounts 10       |      100-10
Tx1 Commits            |        |
Tx2 Commits            |        |
Tx1 Read Wallet 1      90       |
Tx2 Read Wallet 2      |        90

Таким образом, чтобы контролировать это поведение, у вас есть два варианта:

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

Вы можете начать обзор оптимистической блокировки здесь: Оптимистическая блокировка в JPA, как она работает?

...