Здесь the sample project, где воспроизводится исключение.OptimisticLockException с одновременным обновлением JPA под Spring Boot
Этот образец иллюстрирует проблему, когда многие параллельные транзакции изменяют баланс счета. У учетной записи может быть связано несколько объектов Карт. Сделки связаны с порядком и последними по времени. Каждый поток выполняет следующим образом:
- запросы клиента/заказ/{Хашид} 'для первого доступного Поручения данной карты хэш-идентификатор
- клиент начинает новый ТХ для данного заказа - «/ TX/{OrderId}/start '
- клиент завершает tx -'/tx/{txId}/stop/{amount} ', где сумма tx вычитается из баланса Счета.
Entity блокираторы
счет и заказать сущности версионируются с @ javax.persistence.Version. В последнем шаге объект Счет заблокирован с пессимистической блокировки записи:
@Override
public Account getLockedAccount(Integer id) {
final Account account = findOne(id);
em.lock(account, LockModeType.PESSIMISTIC_WRITE);
return account;
}
Тестирование
Чтобы проверить использование параллельного доступа JMeter сценарий SRC/главная/ресурсы/StressTest.jmx. NB: Extra libs должны быть установлены в JMeter для запуска сценария из-за использования JSON Path extractor. С помощью этих специальных настроек на среднем ноутбуке вы можете получить около 10% ошибок для запроса TxEnd:
{
"timestamp":1425407408204,
"status":500,
"error":"Internal Server Error",
"exception":"org.springframework.orm.ObjectOptimisticLockingFailureException",
"message":"Object of class [sample.data.jpa.domain.Account] with identifier [1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [sample.data.jpa.domain.Account#1]",
"path":"/tx/1443/stop/46.4"
}
Вопроса
Несмотря на пессимистическую используя блокировку записи я все еще получаю оптимистическое исключение блокировки. Есть ли другой подход к обеспечению целостности учетной записи без создания очереди выполнения задачи для всех обновлений или методов синхронизации?
UPD: Обходной с задачей исполнителя помещается в another branch. Весна ThreadPoolTaskExecutor
в сочетании с транзакционной задачей устраняет проблему.
Перед использованием EntityManager я попытался @Lock аннотацию: '@Lock (LockModeType.PESSIMISTIC_WRITE) Счет findOne (Integer integer); '. Полную реализацию предыдущей версии можно найти здесь (https://github.com/EvgeniGordeev/spring-jpa-optimistic-lock/blob/dedc33d5f5462819e1b5fb7ce165d14e27480b96/src/main/java/sample/data/jpa/service/AccountRepository. Ява). Внутри Spring SimpleJpaRepository используется тот же эквивалент 'em.find (domainType, id, type, hints)', где hints является текущим LockModeType. –
Так что это не помогает. –