8.2. Seam managed transactions
EJB session beans feature declarative transaction management. The EJB container is able to start a transaction transparently when the bean is invoked, and end it when the invocation ends. If we write a session bean method that acts as a JSF action listener, we can do all the work associated with that action in one transaction, and be sure that it is committed or rolled back when we finish processing the action. This is a great feature, and all that is needed by some Seam applications.
However, there is a problem with this approach. A Seam application may not perform all data access for a request from a single method call to a session bean.
-
The request might require processing by several loosly-coupled components, each of which is called independently from the web layer. It is common to see several or even many calls per request from the web layer to EJB components in Seam.
-
Rendering of the view might require lazy fetching of associations.
The more transactions per request, the more likely we are to encounter atomicity and isolation problems when our application is processing many concurrent requests. Certainly, all write operations should occur in the same transaction!
Hibernate users developed the
"open session in view"
pattern to work around this problem. In the Hibernate community, "open session in view" was historically even more important because frameworks like Spring use transaction-scoped persistence contexts. So rendering the view would cause LazyInitializationException
s when unfetched associations were accessed.
This pattern is usually implemented as a single transaction which spans the entire request. There are several problems with this implementation, the most serious being that we can never be sure that a transaction is successful until we commit it—but by the time the "open session in view" transaction is committed, the view is fully rendered, and the rendered response may already have been flushed to the client. How can we notify the user that their transaction was unsuccessful?
Seam solves both the transaction isolation problem and the association fetching problem, while working around the problems with "open session in view". The solution comes in two parts:
-
use an extended persistence context that is scoped to the conversation, instead of to the transaction
-
use two transactions per request; the first spans the beginning of the update model values phase until the end of the invoke application phase; the second spans the render response phase
In the next section, we'll tell you how to set up a conversation-scope persistence context. But first we need to tell you how to enable Seam transaction management. Note that you can use conversation-scoped persistence contexts without Seam transaction management, and there are good reasons to use Seam transaction management even when you're not using Seam-managed persistence contexts. However, the two facilities were designed to work together, and work best when used together.
8.2.1. Enabling Seam-managed transactions
To make use of
Seam managed transactions
, you need to use TransactionalSeamPhaseListener
in place of SeamPhaseListener
.
<lifecycle>
<phase-listener>
org.jboss.seam.jsf.TransactionalSeamPhaseListener
</phase-listener>
</lifecycle>
Seam transaction management is useful even if you're using EJB 3.0 container-managed persistence contexts. But it is especially useful if you use Seam outside a Java EE 5 environment, or in any other case where you would use a Seam-managed persistence context.