10.3. Seam-managed persistence contexts
If you use Seam outside a Java EE 5 environment, you cannot rely upon the container to manage the persistence context lifestyle. Even within EE 5 environments, propagating the persistence context between loosely-coupled components in a complex application can be difficult and error-prone.
In this case, you will need to use a managed persistence context (for JPA) or a managed session (for Hibernate) in your components. A Seam-managed persistence context is just a built-in Seam component that manages an instance of
EntityManager or Session in the conversation context. You can inject it with @In.
Seam-managed persistence contexts are extremely efficient in a clustered environment. Seam can perform optimizations for container-managed persistence contexts that the EJB3 specification does not allow. Seam supports transparent failover of extended persistence contexts, without replicating any persistence context state between nodes. (We hope to add this support to the next revision of the EJB specification.)
10.3.1. Using a Seam-managed persistence context with JPA
Configuring a managed persistence context is easy. In
components.xml, write:
<persistence:managed-persistence-context name="bookingDatabase" auto-create="true" persistence-unit-jndi-name="java:/EntityManagerFactories/bookingData"/>
This configuration creates a conversation-scoped Seam component named
bookingDatabase, which manages the life cycle of EntityManager instances for the persistence unit (EntityManagerFactory instance) with JNDI name java:/EntityManagerFactories/bookingData.
You must bind the
EntityManagerFactory into JNDI. In JBoss, you can do this by adding the following property setting to persistence.xml.
<property name="jboss.entity.manager.factory.jndi.name" value="java:/EntityManagerFactories/bookingData"/>
Now we can inject our
EntityManager with:
@In EntityManager bookingDatabase;
If you use EJB3, and mark your class or method
@TransactionAttribute(REQUIRES_NEW), then the transaction and persistence context should not propagate to method calls on this object. However, since the Seam-managed persistence context propagates to any component within the conversation, it propagates to methods marked REQUIRES_NEW. Therefore, if you mark a method REQUIRES_NEW, you should access the entity manager with @PersistenceContext.
10.3.2. Using a Seam-managed Hibernate session
Seam-managed Hibernate sessions work in a similar fashion. In
components.xml:
<persistence:hibernate-session-factory name="hibernateSessionFactory"/> <persistence:managed-hibernate-session name="bookingDatabase" auto-create="true" session-factory-jndi-name="java:/bookingSessionFactory"/>
Here,
java:/bookingSessionFactory is the name of the session factory specified in hibernate.cfg.xml.
<session-factory name="java:/bookingSessionFactory"> <property name="transaction.flush_before_completion">true</property> <property name="connection.release_mode">after_statement</property> <property name="transaction.manager_lookup_class"> org.hibernate.transaction.JBossTransactionManagerLookup </property> <property name="transaction.factory_class"> org.hibernate.transaction.JTATransactionFactory </property> <property name="connection.datasource"> java:/bookingDatasource </property> ... </session-factory>
Note
Seam does not synchronize the session with the database, so always enable
hibernate.transaction.flush_before_completion to ensure that the session is automatically synchronized before the JTA transaction commits.
We can now inject a managed Hibernate
Session into our JavaBean components with the following code:
@In Session bookingDatabase;10.3.3. Seam-managed persistence contexts and atomic conversations
Conversation-scoped persistence contexts let you program optimistic transactions spanning multiple server requests, without using
merge(), reloading data at the beginning of each request, or wrestling with exceptions (LazyInitializationException or NonUniqueObjectException).
You can achieve transaction isolation and consistency by using optimistic locking. Both Hibernate and EJB3 make optimistic locking easy with the
@Version annotation.
By default, the persistence context is synchronized with the database (flushed) at the end of each transaction. Sometimes this is desirable, but often we prefer all changes to be held in memory, and only written to the database when the conversation ends successfully. This allows for truly atomic conversations with EJB3 persistence. However, Hibernate provides this feature as a vendor extension to the
FlushModeTypes defined by the specification. We expect 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 entire 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 synchronization to occur:
@End public void commitClaim() { em.flush(); }
You can also set the
flushMode to MANUAL from pages.xml, for example in a navigation rule:
<begin-conversation flush-mode="MANUAL" />
You can set any Seam-managed persistence context to use manual flush mode:
<components xmlns="http://www.jboss.org/schemas/seam/components" xmlns:core="http://www.jboss.org/schemas/seam/core"> <core:manager conversation-timeout="120000" default-flush-mode="manual" /> </components>
Important
When using SMPC in your Stateful bean, manual flush mode is ignored as this mode is a specific Hibernate extension to the JPA specification. Seam cannot control the flush mode of the persistence context on an SFSB. This means there is no manual flush available for SFSB.