Документація розробника Hibernate – Глава V. Блокування

Представляю вашій увазі переклад п'ятої глави офіційній документації Hibernate.

Переклад статті актуальний для версії Hibernate 4.2.19.Final

Зміст
 5.1. Оптимістичні блокування
   5.1.1 Виділений номер версії
   5.1.2. Timestamp
 5.2. Песимістичні блокування

Блокування – це заходи щодо запобігання модифікації даних в реляційній базі даних між часом їх читання, і часом їх використання.
Стратегія блокувань може бути або оптимістичної чи песимістичної.

Стратегії блокувань

Оптимістична
Оптимістичні блокування припускають, що безліч транзакцій можуть завершитися без впливу один на одного, і таким чином можуть виконуватися без блокувань тих ресурсів, на які вони впливають. Перед комітом, кожна транзакція перевіряє, що жодна інша транзакція не модифікувала її дані. Якщо перевірка виявила конфліктні модифікації, транзакція, яка перебуває в стані коміта, відкочується.

Песимістична
Песимістична стратегія передбачає, що паралельні транзакції будуть конфліктувати кожна друг з іншому, і вимагає блокування ресурсів після їх читання, а також її зняття тільки після того, як додаток завершило використання даних.
Hibernate надає механізми для реалізації обох стратегій блокувань у вашому додатку.

5.1. Оптимістичні блокування
Ви можете зберігати версионированные дані, коли ваш додаток використовує довгоживучі транзакції або діалоги, покривають кілька БД-транзакцій. Таким чином, якщо одна і та ж сутність буде модифікуватися двома діалогами, останній діалог, коммитивший зміни, буде сповіщено про конфлікт, і не замінить результати іншого діалогу. Цей підхід гарантує деяку ступінь ізоляції, але при цьому добре масштабується, і досить непогано показує себе в ситуаціях Read-Often Write-Sometimes
Hibernate надає два різних механізму для зберігання версионной інформації – виділений номер версії, або тимчасову мітку (timestamp).

Номер версії
Тимчасова мітка

ВажливоВластивість версії або тимчасової мітки не може бути null для від'єднаних (detached) об'єктів. Hibernate розпізнає будь примірник з версією ( або тимчасовою міткою) дорівнює null transient, в незалежності від інших стратегій unsaved-value* які ви вказуєте. Оголошення null-ового властивості версії або тимчасової мітки – легкий спосіб уникнути проблеми з транзитивным повторним сполукою(transitive reattachment) Hibernate, що є особливо корисним у випадках, де ви використовуєте приєднаніassigned) ідентифікатори або композитні ключі.

* unsaved-value – стратегія визначення операції UPDATE або INSERT для синхронізації з БД, що залежить від значення властивості, проецирующегося з допомогою id version, або timestamp (прим. перекл.)

5.1.1. Виділений номер версії
Механізм номера версії для оптимістичних блокувань надається анотацією Version.

Приклад 5.1. Анотація Version

@Entity
public class Flight implements Serializable {
...
@Version
@Column(name="OPTLOCK")
public Integer getVersion() { ... }
}


Тут властивість версії маппится на колонку OPTLOCK, а менеджер сутностей (entity manager) використовує її для виявлення конфліктуючих оновлень, і запобігання втрати оновлень, які були б перезаписані стратегією last-commit-wins

Колонка версії може бути будь-якого типу, за умови, що ви визначите і реалізуєте підходящий UserVersionType.

Вашій додатком заборонено змінювати номер версії, проставлений Hibernate. Щоб штучно збільшити номер версії, див. опис властивостей LockModeType.OPTIMISTIC_FORCE_INCREMENT або LockModeType.PESSIMISTIC_FORCE_INCREMENT у документації Hibernate Entity Manager. Якщо номер версії згенерований базою даних, наприклад тригером, використовуйте анотацію org.hibernate.annotations.Generated(GenerationTime.ALWAYS).

Приклад 5.2. Оголошення властивості версії hbm.xml

<version
column="version_column"
name="propertyName"
type="typename"
access="field|property|ClassName"
unsaved-value="null|negative|undefined"
generated="never|always"
insert="true|false"
node="element-name/@attribute-name/element/@attribute/."
/>

Ім'я Опис
column Ім'я колонки, в якій знаходиться номер версії.
Опціонально, за замовчуванням таке ж як у імені властивості.
name Ім'я властивості персистентного класу.
type Тип номера версії. Опціонально, за замовчуванням integer.
access Стратегія Hibernate для доступу до значення властивості. Опціонально, за замовчуванням property
unsaved-value Показує, що примірник тільки що створений і тим самим не збережено. Виділяє з від'єднаних сутностей (detached).
Значення за замовчуванням, undefined, показує, що властивість-ідентифікатор не повинен використовуватися. Опціонально.
generated Показує, що властивість версії має генеруватися базою даних.
Опціонально, за замовчуванням never.
insert Включати чи ні колонку версії вираз SQL insert. За замовчуванням true, but ви можете поставити це в false, якщо колонка в БД визначена зі значенням за замовчуванням 0


5.1.2. Timestamp
Тимчасові мітки (timestamps) — менш надійний спосіб оптимістичних блокувань ніж номери версій, який також може бути використаний додатками для інших цілей. Тимчасові мітки використовуються автоматично, якщо ви використовуєте анотацію Version на властивості типу Date або Calendar.

Приклад 5.3. Використання тимчасових міток для оптимістичних блокувань

@Entity
public class Flight implements Serializable {
...
@Version
public Date getLastUpdate() { ... }
}

Hibernate може отримати значення тимчасової мітки з бази даних або JVM, прочитавши значення анотації org.hibernate.annotations.Source. Значення може бути або org.hibernate.annotations.SourceType.DB, або org.hibernate.annotations.SourceType.VM. Поведінка за умовчанням- це використання БД, також використовується, якщо ви не вкажете анотацію.
Тимчасова мітка також може бути згенерована базою даних замість Hibernate, якщо ви використовуєте анотацію org.hibernate.annotations.Generated(GenerationTime.ALWAYS).

Приклад 5.4. Елемент timestamp hbm.xml

<timestamp
column="timestamp_column"
name="propertyName"
access="field|property|ClassName"
unsaved-value="null|undefined"
source="vm|db"
generated="never|always"
node="element-name/@attribute-name/element/@attribute/."
/>

Ім'я Опис
column Ім'я колонки, в якій знаходиться тимчасова мітка. Опціонально, за замовчуванням
таке ж, як і ім'я властивості.
name Ім'я JavaBeans-властивості типу Date або Timestamp у персистентного властивості.
access Стратегія, яку Hibernate використовує для доступу до значення властивості.
Опціонально, за замовчуванням property.
unsaved-value Показує, що примірник тільки що створений і тим самим не збережено. Виділяє
з від'єднаних сутностей (detached). Значення за замовчуванням, undefined, показує
що властивість-ідентифікатор не повинен використовуватися. Опціонально.
source Витягує чи Hibernate мітку з БД або з поточної JVM. БД-мітки вносять додатковий оверхэд, т. до Hibernate потрібно запитувати БД кожен раз для визначення инкремента.
Однак, БД-мітки більш безпечні при використанні в
кластеризованном оточенні.
Не всі діалекти БД підтримують витяг поточних тимчасових міток з БД. Інші можуть бути небезпечні для блокувань, через брак точності.
generated Генерується чи мітки засобами БД. Опціонально, за замовчуванням never.


5.2. Песимістичні блокування
Клас LockMode визначає різні рівні блокувань, які може захоплювати Hibernate.

  • LockMode.WRITE
    Захоплюється автоматично, коли Hibernate оновлює або вставляє рядок.
  • LockMode.UPGRADE
    Захоплюється після явного запиту користувача з використанням SELECT… FOR UPDATE на БД, що підтримують даний синтаксис.
  • LockMode.UPGRADE_NOWAIT
    Захоплюється після явного запиту користувача з використанням SELECT… FOR UPDATE NOWAIT в Oracle
  • LockMode.READ
    Захоплюється автоматично коли Hibernate читає дані під рівнями ізоляції Repeatable Read або Serializable. Може бути повторно захоплений явним запитом користувача.
  • LockMode.NONE
    Відсутність блокування. Всі об'єкти переключаються на цей режим блокування в кінці транзакції. Об'єкти, асоційовані з сесією
    через виклик update() або saveOrUpdate також починають в цьому режимі .
Явний запит користувача, означений вище, відбувається як наслідок будь-яких з наступних дій:
  • Виклик Session.load(), із зазначенням LockMode
  • Виклик Session.lock()
  • Виклик 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 буде використовувати відповідний альтернативний режим замість викидання винятку. Це гарантує переносимість додатків.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.