Каков подход к обновлению строки таблицы в зависимости от данных другой таблицы, когда 2 транзакции происходят одновременно и влияют друг на друга

Я использую Java Hibernate.

Вариант использования:

У меня есть 2 таблицы: A и B. Теперь, если B не содержит строки для accId x со статусом true, тогда статус accId x в таблице A должен быть изменен на ACTIVE, иначе он должен оставаться INACTIVE.

Текущее состояние таблиц A и B: B содержит 2 строки (с id = 1, 2), каждая из которых содержит accId как X и статус True. A содержит 1 строку с accId как X и статусом INACTIVE.

Теперь одновременно приходят 2 вызова для каждой из строк (id = 1, 2), пытающихся сделать статус accId X ложным для соответствующих строк.

Всякий раз, когда приходит какой-либо вызов, чтобы сделать статус любого accId ложным, я делаю статус ложным в таблице B для соответствующего идентификатора строки и проверяю из самой таблицы B, присутствует ли какая-либо другая строка со статусом true для этого идентификатора учетной записи. Если такой строки нет, я меняю статус accId на ACTIVE.

Теперь, в моем случае, если одновременно приходят 2 вызова, оба они проверяют, присутствует ли какая-либо строка со статусом true или нет, так как транзакция пока не зафиксирована и остается в памяти, каждый из них находит, что есть строка со статусом true статус true все еще присутствует. Таким образом, оба они отмечают свой статус как ложный в таблице для соответствующих строк. Но статус accId не меняется на ACTIVE в таблице A.

Как справиться с этой проблемой.


person Talha    schedule 01.05.2016    source источник


Ответы (1)


У вас проблема с параллелизмом: вам нужно заблокировать доступ, когда поступает один из вызовов (первый). Когда поступит 2-й вызов, ему придется подождать, пока не завершится первый вызов и проблема не будет решена. Я считаю, что вы можете указать, что вся таблица будет заблокирована во время транзакции, но я никогда не использовал java hibernate.

Из: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html

11.4. Пессимистическая блокировка

Не предполагается, что пользователи будут тратить много времени на размышления о стратегиях блокировки. Обычно достаточно указать уровень изоляции для соединений JDBC, а затем просто позволить базе данных выполнять всю работу. Однако опытные пользователи могут захотеть получить эксклюзивные пессимистические блокировки или повторно получить блокировки в начале новой транзакции.

Hibernate всегда будет использовать механизм блокировки базы данных; он никогда не блокирует объекты в памяти.

Класс LockMode определяет различные уровни блокировки, которые может получить Hibernate. Блокировка получается следующими механизмами:

LockMode.WRITE is acquired automatically when Hibernate updates or inserts a row.

LockMode.UPGRADE can be acquired upon explicit user request using SELECT ... FOR UPDATE on databases which support that syntax.

LockMode.UPGRADE_NOWAIT can be acquired upon explicit user request using a SELECT ... FOR UPDATE NOWAIT under Oracle.

LockMode.READ is acquired automatically when Hibernate reads data under Repeatable Read or Serializable isolation level. It can be re-acquired by explicit user request.

LockMode.NONE represents the absence of a lock. All objects switch to this lock mode at the end of a Transaction. Objects associated with the session via a call to update() or saveOrUpdate() also start out in this lock mode. 

«Явный запрос пользователя» выражается одним из следующих способов:

A call to Session.load(), specifying a LockMode.

A call to Session.lock().

A call to Query.setLockMode(). 

Если Session.load() вызывается с UPGRADE или UPGRADE_NOWAIT, а запрошенный объект еще не был загружен сеансом, объект загружается с помощью SELECT ... FOR UPDATE. Если load() вызывается для объекта, который уже загружен с менее строгой блокировкой, чем запрошенная, Hibernate вызывает lock() для этого объекта.

Session.lock() выполняет проверку номера версии, если указанный режим блокировки READ, UPGRADE или UPGRADE_NOWAIT. В случае UPGRADE или UPGRADE_NOWAIT используется SELECT ... FOR UPDATE.

Если запрошенный режим блокировки не поддерживается базой данных, Hibernate использует соответствующий альтернативный режим вместо создания исключения. Это гарантирует переносимость приложений.

person Luís Pedro Gonçalves    schedule 01.05.2016
comment
спасибо, я попытался использовать пессимистическое чтение на уровне запроса, но не смог установить время ожидания для второй транзакции, поэтому он столкнулся с LockAcquisitionException. - person Talha; 02.05.2016