Spring Data / Hibernate MS SQL Server уникальное ограничение и состояние гонки

Некоторое время назад я столкнулся с проблемой гонки, когда две отдельные транзакции пытаются одновременно проверить, существует ли запись (по 4 полям), а если нет – создать новую.

Моя среда:

MS SQL Server , Spring Data / JPA / Hibernate

Это была проблема с дублирующимися записями. Я выполнил тест, который имитирует одновременные вызовы и, таким образом, смог (довольно стабильный на 99,99% времени выполнения), чтобы воспроизвести эту проблему.

Сейчас я исправил эту проблему, применив уникальное ограничение по этим 4 полям. В настоящий момент мой тест неспособен воспроизвести эту проблему. Я действительно доволен, но, честно говоря, я не совсем понимаю, как это работает под капотом. Именно поэтому я создал этот вопрос – я не понимаю, почему, например, мой тест не прерывается с ConstraintViolationException то время как обе одновременные транзакции одновременно проверяют наличие записи, а затем пытаются создать ее (каждый из них). По моему мнению, согласно моему тесту – обе транзакции работают одновременно и не должны находить записи во время первой проверки. После этого им следует попытаться создать новые записи, и одна из транзакций должна быть в состоянии сделать это, а другая – с ConstraintViolationException . Но код работает отлично, и все работает без каких-либо исключений.

Существуют ли внутренние механизмы синхронизации на уровне Spring Data / JPA / Hibernate или даже MS SQL Server, которые предотвращают параллельную транзакцию от неправильной работы и позволяют им ждать результатов работы друг от друга? Пожалуйста, объясни. Благодаря !

Короткий ответ

Все зависит от индексов, которые вы указали в таблице, и индексов, используемых вашими запросами в то время. Если разные планы выполнения использовались различными процессами для проверки несуществования строки, они оба возвращали true, и оба добавляли запись из-за того, как SQL Server выдает блокировки ресурсов.

От 1]:

  1. При выполнении операции записи SQL Server не блокирует связанные индексы … только соответствующую строку данных.
  2. При выполнении операции чтения SQL Server блокирует только объекты (например, индексы, строки данных и т. Д.), Которые он нашел и использовал в своем пути доступа.

Добавив уникальное ограничение для этих 4 полей, вы неявно и эффективно добавили индекс покрытия, в результате чего все ваши процессы использовали один и тот же план запросов и, следовательно, получили блокировки ресурсов в том же порядке на тех же объектах.

Длительный ответ

Несоответствие данных при запросе с различными индексами

Для получения более подробной информации об блокировке ресурсов читайте это: [1] https://www.mssqltips.com/sqlservertip/1485/using-sql-server-indexes-to-bypass-locks/

  • Производительность JPA / Hibernate
  • Добавление внешнего ключа в составной первичный ключ и изменения класса сущности JPA
  • Типы данных time и datetime несовместимы с оператором, большим или равным оператору
  • Java JPA / Hibernate с SQL Server - как определить, когда столбцы в db не сопоставлены сущностью?
  • Совместимость объектов JPA для SQL Server и Oracle (проблемы с автоинкрементами)
  • Как установить XACT_ABORT с помощью JPA / Hibernate?
  • JPA getResultList () возвращает BigInteger для MySQL, но Integer для сервера Microsoft SQL
  • JPA - создание первичного ключа Transient
  • Невозможно прочитать таблицу из приложения, а также клиента ms sql при применении @Transactional (распространение = распространение). На уровне сервиса jpa
  • Исключение хранимой процедуры SQL не найдено в JAVA
  • Как обнаружить открытое соединение с Hibernate / JPA?
  • Давайте будем гением компьютера.