Изучаем Java EE 7 - [103]

Шрифт
Интервал


Листинг 6.36. Сущность Book с аннотацией @Version в случае с Integer

>@Entity

>public class Book {

>··@Id @GeneratedValue

>··private Long id;

>··@Version

>··private Integer version;

>··private String title;

>··private Float price;

>··private String description;

>··private String isbn;

>··private Integer nbOfPage;

>··private Boolean illustrations;

>··// Конструкторы, геттеры, сеттеры

>}

Сущность может получить доступ к значению своего свойства version, но не имеет возможности модифицировать его. Только поставщику постоянства разрешено задавать или обновлять значение атрибута version при записи или обновлении объекта в базе данных. Взглянем на пример, иллюстрирующий поведение, которое наблюдается при этом контроле версий. В листинге 6.37 обеспечивается постоянство новой сущности Book в базе данных. Как только происходит фиксация транзакции, поставщик задает для version значение 1. Далее цена книги обновляется и, как только информация сбрасывается в базу данных, номер версии инкрементируется, становясь равным 2.


Листинг 6.37. Транзакции tx1 и tx2, одновременно обновляющие цену книги

>Book book = new Book("H2G2", 21f, "Лучшая IT-книга", "123–456", 321, false);

>tx.begin();

>em.persist(book);

>tx.commit();

>assertEquals(1, book.getVersion());


>tx.begin();

>book.raisePriceByTwoDollars();

>tx.commit();

>assertEquals(2, book.getVersion());

Атрибут version необязателен для использования, но его рекомендуется применять, когда сущность может быть одновременно модифицирована несколькими процессами или потоками. Контроль версий представляет собой ядро оптимистической блокировки и обеспечивает защиту при редких одновременных модификациях сущности. Фактически к сущности может быть автоматически применена оптимистическая блокировка, если у нее имеется свойство, снабженное аннотацией @Version.

Оптимистическая блокировка

Как видно из названия, оптимистическая блокировка основана на том факте, что транзакции в базах данных не конфликтуют друг с другом. Другими словами, высока вероятность того, что транзакция, обновляющая сущность, окажется единственной, которая в действительности будет обновлять сущность в этот промежуток времени. Следовательно, решение о применении блокировки к сущности на самом деле принимается в конце транзакции. Это гарантирует, что обновления сущности будут согласовываться с текущим состоянием базы данных. Результатом транзакций, которые привели бы к нарушению этого ограничения, стало бы генерирование исключения OptimisticLockException, а эти транзакции оказались бы помечены как подлежащие откату.

Как можно было бы сгенерировать исключение OptimisticLockException? Это можно сделать, либо применив явным образом блокировку к сущности (с помощью методов lock или find, которые вы видели ранее, передав LockModeType), либо разрешив поставщику постоянства проверить атрибут, снабженный аннотацией @Version. Использование специальной аннотации @Version в случае с сущностью позволяет менеджеру сущностей применить оптимистическую блокировку, просто сравнив значение атрибута version в экземпляре сущности со значением соответствующего столбца в базе данных. Если атрибут не будет аннотирован с использованием @Version, то менеджер сущностей не сможет применять оптимистическую блокировку автоматически (неявно).

Снова взглянем на пример повышения цены книги. Обе транзакции, tx1 и tx2, получают экземпляр одной и той же сущности Book. В тот момент номер версии сущности Book равен 1. Первая транзакция повышает цену книги на $2 и фиксирует это изменение. Когда информация сбрасывается в базу данных, поставщик постоянства увеличивает номер версии, делая его равным 2. В тот момент вторая транзакция поднимает цену на $5 и фиксирует это изменение. Менеджер сущностей для tx2 понимает, что номер версии в базе данных отличается от того, что имеется у сущности. Это означает, что номер версии был изменен в результате выполнения другой транзакции, из-за чего генерируется исключение OptimisticLockException, как показано на рис. 6.5.


Рис. 6.5. Исключение OptimisticLockException, генерируемое в результате выполнения транзакции tx2


Это поведение по умолчанию, которое наблюдается при использовании аннотации @Version: исключение OptimisticLockException генерируется при сбросе данных (во время фиксации либо с помощью явного вызова метода em.flush()). Вы также можете решать, где вам требуется добавить оптимистическую блокировку, обеспечивая чтение, а затем — блокировку либо чтение и блокировку. Например, код для обеспечения чтения и блокировки выглядел бы следующим образом:

>Book book = em.find(Book.class, 12);

>// Блокировать, чтобы повысить цену

>em.lock(book, LockModeType.OPTIMISTIC);

>book.raisePriceByTwoDollars();

При оптимистической блокировке LockModeType, передаваемый вами в качестве параметра, может принимать два значения: OPTIMISTIC и OPTIMISTIC_FORCE_INCREMENT (или соответственно READ и WRITE, однако эти значения устарели). Единственное отличие заключается в том, что OPTIMISTIC_FORCE_INCREMENT форсирует обновление (инкрементирование) значения столбца version, связанного с сущностью.

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.