Spring Web Flow is a novel java™web framework that extends the spring MVC technology. Application development using Spring Web flow is expanded around the use cases defined as Web streams. Organizing a development workspace based on a Web stream makes the development experience more meaningful and contextual. In addition, the support of Spring Web flow for jpa/hibernate persistence is one of its most important server-side improvements.
Although the SpringSource and spring Web Flow Project groups detail the spring Web flow, its persistence support, especially its flow-management persistence mechanism, is rarely known. This article provides an in-depth overview of Java persistence programming in Spring Web Flow 2, focusing on the persistence of stream management and the persistence context of its basic component-flow scope.
After outlining the basic concepts of Spring Web flow persistence, I'll present a few use cases to show you how to handle read-only and read/write transactions in atomic and non-atomic web streams. In each case, I will explain the basic idea of the preferred transaction strategy and explain its drawbacks. At the end of this article I've summed up some of the Guiding principles for efficient and secure management of transactions in Spring Web flow 2.
This article is intended for experienced Java developers who are familiar with Spring Web Flow 2 and its continuations based architecture. Developers who have used jpa/hibernate in Spring Web flow will benefit a lot from use cases and sample application code.
The persistence Challenge in Jpa/hibernate
In a typical WEB application, there are two main steps to handle user requests: Manipulation processing and view rendering. The primary business logic of an application resides in operation processing. The resulting view rendering provides the data to the view template and displays the view.
In Jpa/hibernate, data (or, more specifically, entity relationships) may be eagerly loaded or deferred to a proxy object. If the persisted context object (JPA Entitymanager or Hibernate session) is closed at the view rendering stage, the entity is detached. Any attempt to access the unloaded relationship on the detached entity will result in a lazyinitializationexception exception.
The Open session in View mode attempts to resolve the lazyinitializationexception exception. When the open session in view mode is implemented as a filter or interceptor, the persisted context object remains open during view rendering. Navigating to an unloaded relationship on a persistent entity triggers other database queries to get the relationship on demand.
One disadvantage of the Open session in View mode is that the persisted context object is efficiently delimited within the user request scope. Therefore, entities stored in the Servlet scope are always detached except for the current request. Detached entities require a merge/reconnect/reload operation to be associated with the current persistence context.
Spring Web Flow uses a different approach, which solves the problem of separating the entity state through the persistence of stream management, or rather, the persistent context object of the flow scope.
The persistence of flow management
Application development in Spring Web flow is based on the concept of web streaming, which often represents a single use case. In many cases, the data changes in the entire Web stream need to be atomic, that is, changes in the flow of different phases or as a whole are saved to the back-end database, or all are canceled, leaving no traces in the database.
Spring Web flows simplifies jpa/hibernate programming in transactional atomic Web streams through the persistence mechanism of flow management. The persistence of flow management is conceptually the same as the Hibernate/seam dialog where data changes made during the Web stream (or page flow in Seam) are cached as dirty entities in the persistent context object of the same flow scope. The SQL insert/update/delete statement is not activated until the end of the stream, and the changes are refreshed once and submitted to the database. (Note that "refresh" and "commit" are different concepts; the former activates a series of SQL insert/update/delete statements to synchronize the dirty entities with their corresponding database values, while the latter only commits database transactions).
Optimisticlockingfailureexception in Flow Management persistence
Optimistic locking is an extremely effective concurrency control method that ensures data integrity without having to place any physical locks in the database. Although not enforced, it is strongly recommended that optimistic locks be used in the persistence of flow management.
The persistence context checks for an entity version when it is refreshed, and if a concurrent modification is checked, it throws a Optimisticlockingfailureexception exception (a staleobjectexception exception in Hibernate). The longer an entity is in memory, the greater the likelihood that its corresponding database value will be modified by another process.
As noted above, in the Open session in View mode, the persistent state of an entity is subject to user requests. Once an entity is detached, a merge/reconnect/reload operation is typically required in subsequent user requests to restore the persistent state of the entity, keeping the entity synchronized with its corresponding database values.
In the persistence of flow management, an entity preserves its persistent state between multiple user requests. Database synchronization is not enforced between user requests, so optimisticlockingfailureexception exceptions are likely to occur. It is important to handle optimisticlockingfailureexception exceptions gracefully, just as you would any check-business exception. (This should be the case even if Optimisticlockingfailureexception is a run-time exception that rolls back to the database transaction.) A common strategy is to give users the opportunity to merge their changes or restart the stream with stale data.