jsr338-experts@jpa-spec.java.net

[jsr338-experts] unsynchronized persistence contexts

From: Linda DeMichiel <linda.demichiel_at_oracle.com>
Date: Fri, 26 Aug 2011 12:00:52 -0700

When we solicited feedback on features for this release, one of the
discussions on the jsr-317 feedback list concerned the ability to
specify a persistence context that was not "synchronized" with regard
to transactions -- i.e., which did not respond to transaction
synchronization notifications. This would offer a cleaner alternative
to the manual flushmode which was decisively rejected by the JPA 1.0
expert group.

JPA already has the notion of a persistence context that is
unsynchronized. This occurs when an application-managed persistence
context is created outside the scope of a JTA transaction, and the
application must notify the entity manager that the persistence
context is to be joined to a subsequently-started transaction by means
of the joinTransaction() method.

The proposal below is a strawman proposal for unsynchronized
container-managed persistence contexts that Mike, Gordon,
and I have collaborated on.

This proposal attempts to define synchronization as orthogonal to the
existing persistence context types and propagation rules. It loosens
some of the restrictions imposed by those types however.
In particular:
  -- Entity managers for unsynchronized transaction-scoped persistence
     contexts can be used to invoke the persist, remove, refresh, and
     merge operations regardless of the presence of an existing transaction.
  -- The notion of extended persistence context is loosened to include
     the use of extended persistence contexts being "bound" to stateless
     session beans in order to capture the ability to propagate extended
     persistence contexts from stateful session beans to stateless
     session beans outside of a transaction.

Please post your feedback to the group, including on the open issues.

thanks,

-Linda

-----------------------------------

Proposal:

A container-managed persistence context can be designated at its point
of creation to be unsynchronized by means of the synchronization
element of the PersistenceContext annotation. Both transaction-scoped
and extended persistence contexts may be designated as unsynchronized.

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
public @interface PersistenceContext {
    String name() default "";
    String unitName() default "";
    PersistenceContextType type default TRANSACTION;
    SynchronizationType synchronization default SYNCHRONIZED;
    PersistenceProperty[] properties() default {};
}

public enum SynchronizationType {
   SYNCHRONIZED,
   UNSYNCHRONIZED
}

A persistence context of type UNSYNCHRONIZED is not enlisted in any
JTA transaction unless explicitly joined to that transaction by the
application.

An unsynchronized persistence context is enlisted in a JTA transaction
and registered for subsequent transaction notifications against that
transaction by invoking the EntityManager joinTransaction() method.
The persistence context remains joined to (synchronized with) the
transaction until the transaction commits or rolls back. After the
transaction commits or rolls back, the persistence context will not be
synchronized with any subsequent transaction unless the joinTransaction
method is invoked in the scope of that subsequent transaction.

A persistence context of type SynchronizationType.UNSYNCHRONIZED must
not be flushed to the database unless it is joined to a transaction.
Both the persistence provider and the application are prohibited from
flushing to the database until the point that a transaction has been
joined. The application's use of queries with pessimistic locks, bulk
updates/delete queries, etc. result in the provider throwing the
TBDException. (If the application has specified FlushMode.AUTO, it
must be ignored by the provider when executing queries.) [Open Issue:
should this be IllegalStateException or a new JPA exception?] After
the persistence context has been enlisted in the JTA transaction,
these operations are again allowed.

The application is permitted to invoke the persist, merge, remove, and
refresh entity lifecycle operations on an entity manager corresponding
to a unsynchronized transaction-scoped persistence context as well as
one corresponding to an unsynchronized extended persistence context
independent of whether a transaction is active.
Such changes in the persistence context can be flushed to the database
either explicitly by the application or by the provider after the
persistence context has been joined to a transaction. If flush() is
not explicitly invoked, flushing may be deferred until commit time
depending on the operations invoked (and the setting of
FlushModeType.)

If an unsynchronized persistence context has not been joined to the
current JTA transaction, rollback of the JTA transaction will have no
effect upon the persistence context. It is recommended that the
persistence provider use a non-JTA datasource for an unsynchronized
persistence context that has not been joined to a JTA transaction to
alleviate the risk of integrating uncommitted changes into the
persistence context in the event that the transaction is later rolled
back.

If an unsynchronized persistence context has been joined to the JTA
transaction, transaction rollback will cause the persistence context
to be cleared and all pre-existing managed and removed instances to
become detached. (See spec section 3.3.2.)

When a JTA transaction exists, an unsynchronized persistence context
is propagated with that transaction according to the rules below (in
the section Requirements for Persistence Context Propagation)
regardless of whether the persistence context has been joined to that
transaction.


Container-managed Extended Persistence Contexts (See spec section
7.6.2)

The rules pertaining to extended persistence contexts are relaxed as
follows: Any EJB component may specify the use of an extended
persistence context. If the persistence context bound to a stateful
session bean is not inherited by any other component, it is the
responsibility of the container to close the persistence context when
the @Remove method of the stateful session bean completes (or the
stateful session bean instance is otherwise destroyed) or when the
method invocation completes (if the component is a stateless session
bean or message-driven bean). [OPEN ISSUE: still need to handle the
singleton session bean case.]


Inheritance of Extended Persistence Contexts (See spec section
7.6.2.1.)

If a component to which an extended persistence context is bound
instantiates a stateful session bean component (executing in the same
EJB container instance), which also specifies an extended persistence
context, the extended persistence context of the first component is
inherited by the second component and bound to it, and this rule
recursively applies--independent of whether transactions are active or
not at the point of the creation. If the second component is a
stateless session bean component that is invoked by a component to
which an extended persistence context is bound, the persistence
context is propagated into the that stateless session bean and bound
to it for the duration of the method invocation.

If the persistence context has been initiated or inherited by any
stateful session bean, the container does not close the persistence
context until all such stateful session beans have been removed or
otherwise destroyed.


Requirements for Persistence Context Propagation
(See section 7.6.3.1)
All the requirements of section 7.6.3.1 still apply. (The word
"existing" in the second sub-bullet should be removed.)
In addition, the following is added to the last bullet point:

Subject to the above requirements, a synchronized persistence context
or an unsynchronized persistence context may be propagated into a
component that specifies an unsynchronized persistence context. An
unsynchronized persistence context may only be propagated into a
component that specifies an unsynchronized persistence context. The
attempt to propagate an unsynchronized persistence context into a
component that specifies a synchronized persistence context causes the
EJBException to be thrown. [OPEN ISSUE: Is this the right exception?
Should we relax this if the PC has been joined to the transaction?]