8.3.3. Seam-managed persistence contexts and atomic conversations
Persistence contexts scoped to the conversation allows you to program optimistic transactions that span multiple requests to the server without the need to use the merge()
operation , without the need to re-load data at the beginning of each request, and without the need to wrestle with the LazyInitializationException
or NonUniqueObjectException
.
As with any optimistic transaction management, transaction isolation and consistency can be achieved via use of optimistic locking. Fortunately, both Hibernate and EJB 3.0 make it very easy to use optimistic locking, by providing the @Version
annotation.
By default, the persistence context is flushed (synchronized with the database) at the end of each transaction. This is sometimes the desired behavior. But very often, we would prefer that all changes are held in memory and only written to the database when the conversation ends successfully. This allows for truly atomic conversations. As the result of a truly stupid and shortsighted decision by certain non-JBoss, non-Sun and non-Sybase members of the EJB 3.0 expert group, there is currently no simple, usable and portable way to implement atomic conversations using EJB 3.0 persistence. However, Hibernate provides this feature as a vendor extension to the FlushModeType
s defined by the specification, and it is our expectation that other vendors will soon provide a similar extension.
Seam lets you specify FlushModeType.MANUAL
when beginning a conversation. Currently, this works only when Hibernate is the underlying persistence provider, but we plan to support other equivalent vendor extensions.
@In EntityManager em; //a Seam-managed persistence context
@Begin(flushMode=MANUAL)
public void beginClaimWizard() {
claim = em.find(Claim.class, claimId);
}
Now, the claim
object remains managed by the persistence context for the rest ot the conversation. We can make changes to the claim:
public void addPartyToClaim() {
Party party = ....;
claim.addParty(party);
}
But these changes will not be flushed to the database until we explicitly force the flush to occur:
@End
public void commitClaim() {
em.flush();
}