Как получение общих и эксклюзивных блокировок работает в Hibernate

Я пытаюсь понять, как уровни изоляции READ COMMITED и READ UNCOMMITED работают в Hibernate, и мне нужно какое-то объяснение.

Есть 2 потока THR1 и THR2, которые выполняют один и тот же метод транзакции (Spring аннотация Transactional с уровнем изоляции READ COMMITED). Назовите транзакции, созданные этими потоками, TRA1 и TRA2 соответственно. Транзакционный метод выглядит следующим образом:

public void updateOrSavePreference(String name, String value) {
  Preference preferenceToUpdate = findPreferenceUsingNamedQuery(name); // line 1. shared read lock acquired (uses HibernateTemplate.findByNamedQueryAndNamedParam(...))
  if (preferenceToUpdate != null) { // line 2.
    preferenceToUpdate.setValue(value); // line 3. exclusive write lock acquired (actually I use the HibernateTemplate.merge(...) method
                                        // instead a setter because the entity type is immutable, but it seems irrelevant for this example)
  } else { // line 4.
    HibernateTemplate.save(preferenceToUpdate); // line 5. exclusive write lock acquired
  }
}

Класс Preference аннотируется Entity (optimisticLock = OptimisticLockType.NONE), чтобы применить модель 2PL для этого объекта (я ошибаюсь?). Я использую базу данных Oracle.

Рассмотрим следующие сценарии:

  1. Предположим, что поток THR1 переходит к строке 1 и запрашивает объект. Если я правильно понимаю, транзакция TRA1, созданная этим потоком, получает общую блокировку чтения для запрашиваемого объекта. Затем, если поток THR2 переходит к строке 3, пытаясь получить исключительную блокировку записи для этого объекта, не следует ли блокировать THR2 до тех пор, пока TRA1 не освободит блокировку чтения?

  2. Предположим, что поток THR1 переходит к строке 3 и получает эксклюзивную блокировку записи для объекта (эксклюзивная блокировка сохраняется до тех пор, пока TRA1 транзакция завершена). Затем поток THR2 переходит к строке 1 и пытается запросить этот объект. Не следует ли блокировать THR2, потому что транзакция TRA2 пытается получить блокировку чтения, в то время как другая транзакция TRA1 удерживает исключительную блокировку записи для этого объекта?

  3. Если я воспроизведу сценарий из пункта 2 для уровня изоляции READ UNCOMMITED, THR2, выполняющий транзакцию TRA2, не увидит изменений, внесенных THR1 в транзакции TRA1 даже после обновление или запрос объекта снова ("оценить выражение" при отладке). Почему?


person Bartosz Popiela    schedule 02.12.2017    source источник


Ответы (1)


Технически фиксация чтения может быть достигнута путем установки блокировок чтения. Но не обязательно. Если ваша СУБД поддерживает MVCC, вы всегда читаете зафиксированные данные (за исключением того, что было изменено в вашей собственной транзакции) без установки блокировки.

Итак, я подозреваю, что вы проводите свои тесты с использованием oracle, mysql (INNODB) или postgres? Все эти СУБД по умолчанию поддерживают MVCC, поэтому они никогда не устанавливают разделяемые блокировки чтения.

Поскольку вы используете базу данных Oracle "MVCC", не будет реализован 2PL-протокол, даже если вы настроите его на своем объекте. Если вы хотите узнать, что на самом деле делается в вашей СУБД в собственных операторах, просто активируйте вывод собственных операторов, как вы можете сделать в persistence.xml:

<property name="hibernate.show_sql" value="true" />

Возможно, вам также стоит взглянуть на уровни изоляции транзакции- Relations-with-locks-on-table или сначала по адресу: блокировки и оракул

person aschoerk    schedule 03.12.2017
comment
Я забыл упомянуть, что класс Preference аннотирован с помощью Entity (optimisticLock = OptimisticLockType.NONE), который, как я подозреваю, применяет модель 2PL для данной сущности. Я ошибся? - person Bartosz Popiela; 03.12.2017
comment
Да, я использую базу данных Oracle. - person Bartosz Popiela; 04.12.2017