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

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


Рис. 6.4. Транзакции № 1 (tx1) и № 2 (tx2), одновременно обновляющие цену книги


Эта проблема конкурентного доступа, при которой «победителем» становится транзакция, которая фиксируется последней, неспецифична для JPA. При работе с базами данных эту проблему приходится решать с давних пор, и были найдены разные решения, позволяющие изолировать одну транзакцию от другой. Распространенный механизм, задействуемый базами данных, — это блокировка строки, в отношении которой выполняется SQL-оператор.

JPA 2.1 использует два разных механизма блокировки (версия JPA 1.0 поддерживала только оптимистическую блокировку).

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

• Пессимистическая блокировка основана на противоположном предположении, в результате блокировка будет применяться к ресурсу до начала операций с ним.

В качества примера из повседневной жизни, подкрепляющего эти концепции, представьте себе «оптимистический и пессимистический переходы через улицу». Там, где движение транспорта совсем неинтенсивно, вы сможете перейти через дорогу, не проверяя, нет ли приближающихся автомобилей. Но вы не сможете так поступить в центре города!

JPA использует разные механизмы блокировки на разных уровнях API-интерфейса. Применение как пессимистической, так и оптимистической блокировки возможно с помощью методов EntityManager.find и EntityManager.refresh (в дополнение к методу lock), а также благодаря JPQL-запросам. Иначе говоря, блокировка может быть обеспечена на уровне менеджера сущностей и на уровне Query с помощью методов, приведенных в табл. 6.5 и 6.6.


Таблица 6.5. Методы менеджера сущностей для блокировки сущностей
МетодОписание
T find(Class entityClass, Object primaryKey, LockModeType lockMode)Выполняет поиск сущности указанного класса и первичного ключа, а затем блокирует ее согласно заданному типу режима блокировки
void lock(Object entity, LockModeType lockMode)Блокирует экземпляр сущности, который содержится в контексте постоянства, согласно заданному типу режима блокировки
void refresh(Object entity, LockModeType lockMode)Обновляет состояние экземпляра из базы данных, перезаписывая изменения, внесенные в сущность, при наличии таковых, и блокирует ее согласно заданному типу режима блокировки
LockModeType getLockMode(Object entity)Извлекает значение текущего режима блокировки для экземпляра сущности

Таблица 6.6. Методы Query для блокировки JPQL-запросов
МетодОписание
LockModeType getLockMode()Извлекает значение текущего режима блокировки для запроса
Query setLockMode(LockModeType lockMode)Задает тип режима блокировки для использования при выполнении запроса

Каждый из этих методов принимает LockModeType в качестве параметра, который, в свою очередь, может хранить разные значения:

• OPTIMISTIC — применяет оптимистическую блокировку;

• OPTIMISTIC_FORCE_INCREMENT — применяет оптимистическую блокировку и форсирует инкрементирование значения столбца version, связанного с сущностью (см. следующий подраздел «Контроль версий»);

• PESSIMISTIC_READ — применяет пессимистическую блокировку без необходимости в повторном чтении данных в конце транзакции для обеспечения блокировки;

• PESSIMISTIC_WRITE — применяет пессимистическую блокировку и форсирует сериализацию между транзакциями, которые пытаются обновить сущность;

• PESSIMISTIC_FORCE_INCREMENT — применяет пессимистическую блокировку и форсирует инкрементирование значения столбца version, связанного с сущностью (см. подраздел «Контроль версий» далее);

• NONE — определяет, что не должен использоваться никакой механизм блокировки.

Вы можете задавать эти параметры во многих местах в зависимости от того, как необходимо указать блокировки. Вы можете обеспечить чтение, а затем — блокировку.

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

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

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

>book.raisePriceByTwoDollars();

Либо вы можете обеспечить чтение и блокировку.

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

>// Блокировка уже применена к сущности Book, повысить цену

>book.raisePriceByTwoDollars();

Конкурентный доступ и блокировки являются ключевыми мотиваторами для контроля версий.

Контроль версий

В случае со спецификациями Java применяется контроль версий: Java SE 5.0, Java SE 6.0, EJB 3.1, JAX-RS 1.0 и т. д. При выходе новой версии JAX-RS ее номер увеличивается и вы переходите на JAX-RS 1.1. JPA использует этот точный механизм, когда вам необходимо присвоить номера версий сущностям. Таким образом, когда вы в первый раз обеспечите постоянство сущности в базе данных, она получит номер версии, равный 1. Позднее, если вы обновите атрибут и зафиксируете это изменение в базе данных, номер версии сущности будет равен уже 2 и т. д. Номер версии будет модифицироваться при каждом внесении изменений в сущность.

Чтобы это происходило, у сущности должен иметься атрибут для сохранения номера версии, снабженный аннотацией @Version. Он в дальнейшем отображается в столбец в базе данных. К числу типов атрибутов, поддерживающих контроль версий, относятся int, Integer, short, Short, long, Long и Timestamp. В листинге 6.36 показано, как добавить атрибут version в код сущности Book.


Рекомендуем почитать
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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.