Spring Web Flow — управление персистентностью (flow managed persistence)
7. Управление персистентностью
7.1. Введение
Большинство приложений получают доступ к данным несколькими способами. Часть изменяемых данных доступны для редактирования несколькими пользователями и, следовательно, требуют поддержку транзакций при доступе к данным. Данные часто преобразуют реляционные наборы данных к объектам в предметной области для обеспечения их обработки в приложении. Web Flow предоставляет «управление персистентностью в потоке», с помощью которой поток может создавать, фиксировать, и закрывать объект персистентости. Web Flow включает обе технологии для работы с объектами персистености — Hibernate и JPA.
Отдельно от управления персистентностью с помощью потока, существует шаблон, который полностью инкапсулирует управление с помощью PersistenceContext внутри сервисного слоя вашего приложения. В этом случае веб-слой не связывается с персистентностью, а работает с совершенно отдельными объектами, которые устанавливаются и возвращаются сервисный слоем приложения. Эта глава сфокусирована на поточном управлении персистентностью и будет исследовано как и где используется эта функция.
7.2. FlowScoped PersistenceContext
Этот шаблон создает PersistenceContext в области flowScope при старте потока, используя контекст для доступа к данным в ходе выполнения потока, и подтверждает изменения сущностей персистенстности при завершении. Этот шаблон обеспечивает изоляцию промежуточных правок до подтверждения изменений в базе в конце выполнения потока. Этот шаблон часто используется в сочетании с оптимистичной стратегией блокировки (optimistic locking strategy) для защиты целостности данных при параллельном доступе нескольких пользователей. Для поддержки сохранения и перезапуска хода выполнения потока на длительный период времени, необходимо использовать надежное хранилище для состояния потока. Если возможность сохранения и перезапуска не требуется, то достаточно использовать стандартное хранилище на основе HTTP-сессии для хранения состояния потока. В этом случае, истечение срока действия сессии или прерывание до подтверждения изменений может привести к потери произведенных изменений.
Для использования шаблона FlowScoped PersistenceContext вначале необходимо отметить поток как persistence-context:
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> <persistence-context /> </flow> |
Далее правильно настроить FlowExecutionListener для доступа к этом шаблону в вашем потоке. При использовании Hibernate — зарегистрировать HibernateFlowExecutionListener. При использовании JPA — JpaFlowExecutionListener.
1 2 3 4 5 6 7 8 9 10 11 |
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"> <webflow:flow-execution-listeners> <webflow:listener ref="jpaFlowExecutionListener" /> </webflow:flow-execution-listeners> </webflow:flow-executor> <bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener"> <constructor-arg ref="entityManagerFactory" /> <constructor-arg ref="transactionManager" /> </bean> |
Для запуска подтверждения изменений по окончанию необходимо указать в end-state атрибут commit:
1 |
<end-state id="bookingConfirmed" commit="true" /> |
Вот и всё. Когда ваш поток запускается, слушатель выделит новый EntityManager в flowScope. На этот EntityManager можно получить ссылку в любое время внутри вашего потока используя специальную переменную persistenceContext. Кроме того любой доступ к данным, который происходит с помощью управляемого Spring объекта доступа к данным, использует EntityManager автоматически. Операции доступа к данным такого рода должны быть всегда не транзакционными или быть транзакциями только для чтения, для поддержки изоляции от промежуточных изменений.
7.3. Персистентность, управляемая потоком и подпотоки
Управляемый потоком PersistenceContext автоматически распространяется к подпотокам, предполагая, что подпоток так же имеет доступ к переменной <persistence-context/>. Когда подпоток повторно использует PersistenceContext, созданный родительским потоком, то он игнорирует флаги подтверждения изменений при достижении конечного состояния, таким образом откладывая окончательное решение (подтверждать или нет) его родителя.
1