As you saw in Chapter 7, session beans can interact directly with the
database as easily as they can manage the workflow of other beans.
The ProcessPayment bean, for example, makes inserts into the
PAYMENT
table when the
byCredit()
method is invoked. The TravelAgent bean
queries the database directly when the
listAvailableCabins()
method is invoked. With
stateless session beans like ProcessPayment, there is no
conversational state, so each method invocation must make changes to
the database immediately. With stateful session beans, however, we
may not want to make changes to the database until the transaction is
complete. Remember, a stateful session bean can be just one
participant out of many in a transaction, so it may be advisable to
postpone database updates until the entire transaction is committed
or to avoid updates if it’s rolled back.
There are several different
scenarios in which a stateful session bean would want to cache
changes before applying them to the database. In Chapter 9, we will take a look at modeling entity
business concepts in stateful session beans that implement the
SessionSynchronization
interface. These sessions
may have their methods invoked many times before writing to the
database. For example, think of a shopping cart implemented by a
stateful session bean that accumulates several items for purchase. If
the bean implements SessionSynchronization
, it can
cache the items and only write them to the database when the
transaction is complete.
The javax.ejb.SessionSynchronization
interface
allows a session bean to receive additional notification of the
session’s involvement in transactions. The addition of these
transaction callback methods by the
SessionSynchronization
interface expands the
bean’s awareness of its life cycle to include a new state, the
Transactional Method-Ready state. This third
state, although not discussed in Chapter 7, is
always a part of the life cycle of a transactional stateful session
bean. Implementing the SessionSynchronization
interface simply makes it visible to the bean. Figures Chapter 8 and Figure 8.13 show the
stateful session bean with the additional state in EJB 1.1 and EJB
1.0.
The
SessionSynchronization
interface has the following
definition:
package javax.ejb; public interface javax.ejb.SessionSynchronization { public abstract void afterBegin() throws RemoteException; public abstract void beforeCompletion() throws RemoteException; public abstract void afterCompletion(boolean committed) throws RemoteException; }
When a method of the SessionSynchronization bean is invoked outside of a transaction scope, the method executes in the Method-Ready state as discussed in Chapter 7. However, when a method is invoked within a transaction scope (or creates a new transaction), the bean moves into the Transactional Method-Ready state.
When a transactional method is invoked
on a bean, the bean becomes part of the transaction. This causes the
afterBegin()
callback method defined in the
SessionSynchronization
interface to be invoked.
This method should take care of reading any data from the database
and storing the data in the bean’s instance fields. The
afterBegin()
method is called before the EJB
object delegates the business method invocation to the bean instance.
When the afterBegin()
callback method is done, the
business method originally invoked by the client is executed on the
bean instance. Any subsequent business methods invoked within the
same transaction will be delegated directly to the bean instance.
Once a stateful session bean is a part of a transaction—whether
it implements SessionSynchronization
or
not—it cannot be accessed by any other transactional context.
This is true regardless of whether the client tries to access the
bean with a different context or the bean’s own method creates
a new context. If, for example, a method with a transaction attribute
of Requires New is invoked, the new
transactional context causes an error to be thrown. Since the
attributes Not Supported and
Never (EJB 1.1 only) imply a different
transactional context (no context), invoking a method with thesex
attributes also causes an error. A stateful session bean cannot be
removed while it is involved in a transaction. This means that
invoking ejbRemove()
while the bean is in the
middle of a transaction will cause an error to be thrown.
At some point, the transaction in which the bean has been enrolled
will come to an end. If the transaction is committed, the bean will
be notified through its beforeCompletion()
method.
At this time, the bean should write its cached data to the database.
If the transaction is rolled back, the
beforeCompletion()
method will not be invoked,
avoiding the pointless effort of writing changes that won’t be
committed to the database.
The afterCompletion()
method is always invoked,
whether the transaction ended successfully with a commit or
unsuccessfully with a rollback. If the transaction was a
success—which means that beforeCompletion()
was invoked—the committed parameter of the
afterCompletion()
method will be
true
. If the transaction was unsuccessful,
committed
will be false
.
It may be desirable to reset the stateful session bean’s
instance variables to some initial state if the
afterCompletion()
method indicates that the
transaction
was rolled back.