blob: 7ec7d142f2294deeee8a2fc32e0552ca7a70174c [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<chapter id="ref_guide_runtime">
<title>
Runtime Extensions
</title>
<para>
This chapter describes OpenJPA extensions to the standard JPA
interfaces, and outlines some additional features of the OpenJPA runtime.
</para>
<section id="ref_guide_runtime_arch">
<title>
Architecture
</title>
<para>
Internally, OpenJPA does not adhere to any persistence specification. The
OpenJPA kernel has its own set of APIs and components. Specifications like JPA
and JDO are simply different "personalities" that OpenJPA's native kernel
can adopt.
</para>
<para>
As an OpenJPA user, you will not normally see beneath
OpenJPA's JPA personality. OpenJPA allows you to access its feature set without
leaving the comfort of JPA. Where OpenJPA goes beyond standard JPA
functionality, we have crafted JPA-specific APIs to each OpenJPA extension for
as seamless an experience as possible.
</para>
<para>
When writing OpenJPA plugins or otherwise extending the OpenJPA runtime,
however, you will use OpenJPA's native APIs. So that you won't feel lost, the
list below associates each specification interface with its backing native
OpenJPA component:
</para>
<itemizedlist>
<listitem>
<para>
<classname>javax.persistence.EntityManagerFactory</classname>: <emphasis>
<classname>org.apache.openjpa.kernel.BrokerFactory</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>javax.persistence.EntityManager</classname>: <emphasis><classname>
org.apache.openjpa.kernel.Broker</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>javax.persistence.Query</classname>: <emphasis><classname>
org.apache.openjpa.kernel.Query</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>org.apache.openjpa.persistence.Extent</classname>: <emphasis>
<classname>org.apache.openjpa.kernel.Extent</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>org.apache.openjpa.persistence.StoreCache</classname>: <emphasis>
<classname>org.apache.openjpa.datacache.DataCache</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>org.apache.openjpa.persistence.QueryResultCache</classname>:
<emphasis><classname>org.apache.openjpa.datacache.QueryCache</classname>
</emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>org.apache.openjpa.persistence.FetchPlan</classname>: <emphasis>
<classname>org.apache.openjpa.kernel.FetchConfiguration</classname></emphasis>
</para>
</listitem>
<listitem>
<para>
<classname>org.apache.openjpa.persistence.Generator</classname>: <emphasis>
<classname>org.apache.openjpa.kernel.Seq</classname></emphasis>
</para>
</listitem>
</itemizedlist>
<para>
The <link linkend="ref_guide_runtime_openjpapersistence"><classname>
org.apache.openjpa.persistence.OpenJPAPersistence</classname></link> helper
allows you to convert between <classname>EntityManagerFactories</classname> and
<classname>BrokerFactories</classname>, <classname>EntityManager</classname>s
and <classname>Broker</classname>s.
</para>
<section id="ref_guide_runtime_broker_finalization">
<title>
Broker Finalization
</title>
<indexterm zone="ref_guide_runtime_broker_finalization">
<primary>
EntityManager
</primary>
<secondary>
finalizing
</secondary>
<tertiary>
clean-up
</tertiary>
</indexterm>
<para>
Outside of a Java EE application server or other JPA persistence container
environment, the default OpenJPAEntityManager implementation automatically
closes itself during instance finalization. This guards against accidental
resource leaks that may occur if a developer fails to explicitly close
EntityManagers when finished with them, but it also incurs a scalability
bottleneck, since the JVM must perform synchronization during instance creation,
and since the finalizer thread will have more instances to monitor. To avoid
this overhead, set the
<link linkend="openjpa.BrokerImpl"><literal>openjpa.BrokerImpl</literal></link>
configuration property to <literal>non-finalizing</literal>.
</para>
</section>
<section id="ref_guide_runtime_broker_extension">
<title>
Broker Customization and Eviction
</title>
<indexterm zone="ref_guide_runtime_broker_extension">
<primary>
OpenJPAEntityManager
</primary>
<secondary>
extending
</secondary>
</indexterm>
<para>
As a <link linkend="ref_guide_conf_plugins">plugin string</link>, this property
can be used to configure the <classname> BrokerImpl</classname> with the
following properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>EvictFromDataCache</literal>: When evicting an object through the
<methodname>OpenJPAEntityManager.evict</methodname> methods, whether to also
evict it from the OpenJPA's <link linkend="ref_guide_cache">data cache</link>.
Defaults to <literal>false</literal>.
</para>
</listitem>
</itemizedlist>
<example id="ref_guide_runtime_pm_evictex">
<title>
Evict from Data Cache
</title>
<programlisting>
&lt;property name="openjpa.BrokerImpl" value="EvictFromDataCache=true"/&gt;
</programlisting>
</example>
<para>
Additionally, some advanced users may want to add capabilities to OpenJPA's
internal <ulink url="../javadoc/org/apache/openjpa/kernel/BrokerImpl.html">
<classname>org.apache.openjpa.kernel.BrokerImpl</classname></ulink>. You can
configure OpenJPA to use a custom subclass of <classname>BrokerImpl</classname>
with the <link linkend="openjpa.BrokerImpl"><literal>openjpa.BrokerImpl
</literal></link> configuration property. Set this property to the full class
name of your custom subclass. When implementing your subclass, consider the
finalization issues mentioned in
<xref linkend="ref_guide_runtime_broker_finalization"/>. It may be appropriate
to create a subtype of both
<ulink url="../javadoc/org/apache/openjpa/kernel/BrokerImpl.html">
<classname>org.apache.openjpa.kernel.BrokerImpl</classname></ulink> and
<ulink url="../javadoc/org/apache/openjpa/kernel/FinalizingBrokerImpl.html">
<classname>org.apache.openjpa.kernel.FinalizingBrokerImpl</classname></ulink>.
</para>
</section>
</section>
<section id="ref_guide_runtime_jpa">
<title>
JPA Extensions
</title>
<para>
The following sections outline the runtime interfaces you can use to access
OpenJPA-specific functionality from JPA. Each interface contains services and
convenience methods missing from the JPA specification. OpenJPA strives to use
the same naming conventions and API patterns as standard JPA methods in all
extensions, so that OpenJPA extension APIs feel as much as possible like
standard JPA.
</para>
<para>
You may have noticed the examples throughout this document using the
<methodname>OpenJPAPersistence.cast</methodname> methods to cast from standard
JPA interfaces to OpenJPA extended interfaces. This is the recommended practice.
Some application server vendors may proxy OpenJPA's JPA implementation,
preventing a straight cast. <classname>OpenJPAPersistence</classname>'s
<methodname>cast</methodname> methods work around these proxies.
</para>
<programlisting>
public static OpenJPAEntityManagerFactory cast(EntityManagerFactory emf);
public static OpenJPAEntityManager cast(EntityManager em);
public static OpenJPAQuery cast(Query q);
</programlisting>
<para>
We provide additional information on the <classname>OpenJPAPersistence
</classname> helper <link linkend="ref_guide_runtime_openjpapersistence">
below</link>.
</para>
<section id="ref_guide_runtime_emfactory">
<title>
OpenJPAEntityManagerFactory
</title>
<indexterm zone="ref_guide_runtime_emfactory">
<primary>
OpenJPAEntityManagerFactory
</primary>
</indexterm>
<indexterm>
<primary>
EntityManagerFactory
</primary>
<secondary>
OpenJPA extensions
</secondary>
<see>
OpenJPAEntityManagerFactory
</see>
</indexterm>
<para>
The <classname>org.apache.openjpa.persistence.OpenJPAEntityManagerFactory
</classname> interface extends the basic <classname>
javax.persistence.EntityManagerFactory</classname> with OpenJPA-specific
features. The <classname>OpenJPAEntityManagerFactory</classname> offers APIs to
access the OpenJPA data and query caches and to perform other OpenJPA-specific
operations. See the
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.html">
interface Javadoc</ulink> for details.
</para>
</section>
<section id="ref_guide_runtime_em">
<title>
OpenJPAEntityManager
</title>
<indexterm zone="ref_guide_runtime_em">
<primary>
OpenJPAEntityManager
</primary>
</indexterm>
<indexterm>
<primary>
EntityManager
</primary>
<secondary>
OpenJPA extensions
</secondary>
<see>
OpenJPAEntityManager
</see>
</indexterm>
<para>
All OpenJPA <classname>EntityManager</classname>s implement the
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
<classname>org.apache.openjpa.persistence.OpenJPAEntityManager</classname>
</ulink> interface. This interface extends the standard <classname>
javax.persistence.EntityManager</classname>. Just as the standard <classname>
EntityManager</classname> is the primary window into JPA services, the
<classname>OpenJPAEntityManager</classname> is the primary window from JPA into
OpenJPA-specific functionality. We strongly encourage you to investigate the API
extensions this interface contains.
</para>
</section>
<section id="ref_guide_runtime_jpaquery">
<title>
OpenJPAQuery
</title>
<indexterm zone="ref_guide_runtime_jpaquery">
<primary>
OpenJPAQuery
</primary>
</indexterm>
<indexterm>
<primary>
Query
</primary>
<secondary>
OpenJPA extensions
</secondary>
<see>
OpenJPAQuery
</see>
</indexterm>
<para>
OpenJPA extends JPA's standard query functionality with the <classname>
org.apache.openjpa.persistence.OpenJPAQuery</classname> interface. See its
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAQuery.html">Javadoc
</ulink> for details on the convenience methods it provides.
</para>
</section>
<section id="ref_guide_runtime_jpaextent">
<title>
Extent
</title>
<indexterm zone="ref_guide_runtime_jpaextent">
<primary>
Extent
</primary>
</indexterm>
<indexterm>
<primary>
Extent
</primary>
<secondary>
OpenJPA extensions
</secondary>
<see>
OpenJPAExtent
</see>
</indexterm>
<para>
An <classname>Extent</classname> is a logical view of all persistent instances
of a given entity class, possibly including subclasses. OpenJPA adds the
<ulink url="../javadoc/org/apache/openjpa/persistence/Extent.html"><classname>
org.apache.openjpa.persistence.Extent</classname></ulink> class to the set of
Java Persistence APIs. The following code illustrates iterating over all
instances of the <classname>Magazine</classname> entity, without subclasses:
</para>
<example id="ref_guide_runtime_jpaextentex">
<title>
Using a JPA Extent
</title>
<programlisting>
import org.apache.openjpa.persistence.*;
...
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
Extent&lt;Magazine&gt; mags = kem.createExtent(Magazine.class, false);
for (Magazine m : mags)
processMagazine(m);
</programlisting>
</example>
</section>
<section id="ref_guide_runtime_jpacache">
<title>
StoreCache
</title>
<indexterm zone="ref_guide_runtime_jpacache">
<primary>
StoreCache
</primary>
</indexterm>
<para>
In addition to the <classname>EntityManager</classname> object cache the JPA
specification provides access to a second level cache via the
javax.persistence.Cache interface. OpenJPA provides further extensions via
the org.apache.openjpa.persistence.StoreCache interface documented at
<ulink url="../javadoc/org/apache/openjpa/persistence/StoreCache.html">
<classname>org.apache.openjpa.persistence.StoreCache</classname></ulink>.
<xref linkend="ref_guide_cache"/> has detailed information on OpenJPA's
data caching system, including the <classname>StoreCache</classname> facade.
</para>
</section>
<section id="ref_guide_runtime_jpaquerycache">
<title>
QueryResultCache
</title>
<indexterm zone="ref_guide_runtime_jpaquerycache">
<primary>
QueryResultCache
</primary>
</indexterm>
<para>
OpenJPA can cache query results as well as persistent object data. The
<ulink url="../javadoc/org/apache/openjpa/persistence/QueryResultCache.html">
<classname>org.apache.openjpa.persistence.QueryResultCache</classname></ulink>
is an JPA-flavored facade to OpenJPA's internal query cache. See
<xref linkend="ref_guide_cache_query"/> for details on query caching in
OpenJPA.
</para>
</section>
<section id="ref_guide_runtime_jpafetch">
<title>
FetchPlan
</title>
<indexterm zone="ref_guide_runtime_jpafetch">
<primary>
FetchPlan
</primary>
</indexterm>
<indexterm>
<primary>
eager fetching
</primary>
<seealso>
FetchPlan
</seealso>
</indexterm>
<para>
Many of the aforementioned OpenJPA interfaces give you access to an <classname>
org.apache.openjpa.persistence.FetchPlan</classname> instance. The <classname>
FetchPlan</classname> allows you to exercise some control over how objects are
fetched from the datastore, including <link linkend="ref_guide_dbsetup_lrs">
large result set support</link>, <link linkend="ref_guide_fetch">custom fetch
groups</link>, and <link linkend="ref_guide_locking">lock levels</link>.
</para>
<para>
OpenJPA goes one step further, extending <classname>FetchPlan</classname> with
<ulink url="../javadoc/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.html">
<classname>org.apache.openjpa.persistence.jdbc.JDBCFetchPlan</classname></ulink>
to add additional JDBC-specific tuning methods. Unless you have customized
OpenJPA to use a non-relational back-end (see
<xref linkend="ref_guide_enterprise_abstractstore"/> ), all <classname>
FetchPlan</classname>s in OpenJPA implement <classname>
JDBCFetchPlan</classname>, so feel free to cast to this interface.
</para>
<para>
Fetch plans pass on from parent components to child components. The <classname>
EntityManagerFactory</classname> settings (via your configuration properties)
for things like the fetch size, result set type, and custom fetch groups are
passed on to the fetch plan of the <classname>EntityManager</classname>s it
produces. The settings of each <classname>EntityManager</classname>, in turn,
are passed on to each <classname>Query</classname> and <classname>Extent
</classname> it returns. Note that the opposite, however, is not true. Modifying
the fetch plan of a <classname>Query</classname> or <classname>Extent
</classname> does not affect the <classname>EntityManager</classname>'s
configuration. Likewise, modifying an <classname>EntityManager</classname>'s
configuration does not affect the <classname> EntityManagerFactory</classname>.
</para>
<para>
<xref linkend="ref_guide_fetch"/> includes examples using <classname>
FetchPlan</classname>s.
</para>
</section>
<section id="ref_guide_runtime_openjpaentitytransaction">
<title>
OpenJPAEntityTransaction
</title>
<indexterm zone="ref_guide_runtime_openjpaentitytransaction">
<primary>
OpenJPAEntityTransaction
</primary>
</indexterm>
<para>
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityTransaction.html">
<classname>org.apache.openjpa.persistence.OpenJPAEntityTransaction</classname></ulink>
extends <classname>javax.persistence.EntityTransaction</classname> to provide
additional transaction-debugging capabilities and some concurrency-related
commit and rollback features.
</para>
</section>
<section id="ref_guide_runtime_openjpapersistence">
<title>
OpenJPAPersistence
</title>
<indexterm zone="ref_guide_runtime_openjpapersistence">
<primary>
OpenJPAPersistence
</primary>
</indexterm>
<para>
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAPersistence.html">
<classname>org.apache.openjpa.persistence.OpenJPAPersistence</classname></ulink>
is a static helper class that adds OpenJPA-specific utility methods to
<classname>javax.persistence.Persistence</classname>.
</para>
</section>
</section>
<section id="ref_guide_locking">
<title>
Object Locking
</title>
<indexterm zone="ref_guide_locking">
<primary>
locking
</primary>
</indexterm>
<para>
Controlling how and when objects are locked is an important part of maximizing
the performance of your application under load. This section describes OpenJPA's
APIs for explicit locking, as well as its rules for implicit locking.
</para>
<section id="ref_guide_locking_default">
<title>
Configuring Default Locking
</title>
<indexterm zone="ref_guide_locking_default">
<primary>
locking
</primary>
<secondary>
defaults configuration
</secondary>
</indexterm>
<para>
<indexterm>
<primary>
locking
</primary>
<secondary>
levels
</secondary>
</indexterm>
<indexterm>
<primary>
ReadLockLevel
</primary>
</indexterm>
<indexterm>
<primary>
WriteLockLevel
</primary>
</indexterm>
You can control OpenJPA's default transactional read and write lock levels
through the <link linkend="openjpa.ReadLockLevel"><literal>
openjpa.ReadLockLevel</literal></link> and
<link linkend="openjpa.WriteLockLevel"><literal>openjpa.WriteLockLevel</literal>
</link> configuration properties. Each property accepts a value of <literal>
none</literal>, <literal>read</literal>, <literal>write</literal>,
<literal>optimistic</literal>, <literal>optimistic-force-increment</literal>,
<literal>pessimistic-read</literal>, <literal>pessimistic-write</literal>,
<literal>pessimistic-force-increment</literal>, or a number
corresponding to a lock level defined by the
<link linkend="ref_guide_locking_lockmgr">lock manager</link> in use. These
properties apply only to non-optimistic transactions; during optimistic
transactions, OpenJPA never locks objects by default.
</para>
<para>
<indexterm>
<primary>
LockTimeout
</primary>
</indexterm>
<indexterm>
<primary>
locking
</primary>
<secondary>
timeout
</secondary>
</indexterm>
You can control the default amount of time OpenJPA will wait when trying to
obtain locks through the <link linkend="openjpa.LockTimeout"><literal>
openjpa.LockTimeout</literal></link> configuration property. Set this property
to the number of milliseconds you are willing to wait for a lock before OpenJPA
will throw an exception, or to -1 for no limit. It defaults to -1.
</para>
<example id="ref_guide_locking_default_conf">
<title>
Setting Default Lock Levels
</title>
<programlisting>
&lt;property name="openjpa.ReadLockLevel" value="none"/&gt;
&lt;property name="openjpa.WriteLockLevel" value="write"/&gt;
&lt;property name="openjpa.LockTimeout" value="30000"/&gt;
</programlisting>
</example>
</section>
<section id="ref_guide_locking_runtime">
<title>
Configuring Lock Levels at Runtime
</title>
<indexterm zone="ref_guide_locking_runtime">
<primary>
locking
</primary>
<secondary>
runtime configuration
</secondary>
</indexterm>
<para>
At runtime, you can override the default lock levels through the <classname>
FetchPlan</classname> interface described above. At the beginning of each
datastore transaction, OpenJPA initializes the <classname> EntityManager
</classname>'s fetch plan with the default lock levels and timeouts described
in the previous section. By changing the fetch plan's locking properties, you
can control how objects loaded at different points in the transaction are
locked. You can also use the fetch plan of an individual <classname>Query
</classname> to apply your locking changes only to objects loaded through that
<classname>Query</classname>.
</para>
<programlisting>
public LockModeType getReadLockMode();
public FetchPlan setReadLockMode(LockModeType mode);
public LockModeType getWriteLockMode();
public FetchPlan setWriteLockMode(LockModeType mode);
long getLockTimeout();
FetchPlan setLockTimeout(long timeout);
</programlisting>
<para>
Controlling locking through these runtime APIs works even during optimistic
transactions. At the end of the transaction, OpenJPA resets the fetch plan's
lock levels to <literal>none</literal>. You cannot lock objects outside of a
transaction.
</para>
<example id="ref_guide_locking_fetch">
<title>
Setting Runtime Lock Levels
</title>
<programlisting>
import org.apache.openjpa.persistence.*;
...
EntityManager em = ...;
em.getTransaction().begin();
// load stock we know we're going to update at write lock mode
Query q = em.createQuery("select s from Stock s where symbol = :s");
q.setParameter("s", symbol);
OpenJPAQuery oq = OpenJPAPersistence.cast(q);
FetchPlan fetch = oq.getFetchPlan();
fetch.setReadLockMode(LockModeType.WRITE);
fetch.setLockTimeout(3000); // 3 seconds
Stock stock = (Stock) q.getSingleResult();
// load an object we don't need locked at none lock mode
fetch = OpenJPAPersistence.cast(em).getFetchPlan();
fetch.setReadLockMode(null);
Market market = em.find(Market.class, marketId);
stock.setPrice(market.calculatePrice(stock));
em.getTransaction().commit();
</programlisting>
</example>
</section>
<section id="ref_guide_locking_apis">
<title>
Object Locking APIs
</title>
<indexterm zone="ref_guide_locking_apis">
<primary>
locking
</primary>
<secondary>
runtime APIs
</secondary>
</indexterm>
<para>
In addition to allowing you to control implicit locking levels, OpenJPA provides
explicit APIs to lock objects and to retrieve their current lock level.
</para>
<programlisting>
public LockModeType OpenJPAEntityManager.getLockMode(Object pc);
</programlisting>
<para>
Returns the level at which the given object is currently locked.
</para>
<para>
In addition to the standard
<ulink url="http://download.oracle.com/javaee/6/api/javax/persistence/EntityManager.html">
<methodname>EntityManager.lock(Object, LockModeType)</methodname></ulink>
method, the
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
<classname>OpenJPAEntityManager</classname></ulink> exposes the following
methods to lock objects explicitly:
</para>
<programlisting>
public void lock(Object pc);
public void lock(Object pc, LockModeType mode, long timeout);
public void lockAll(Object... pcs);
public void lockAll(Object... pcs, LockModeType mode, long timeout);
public void lockAll(Collection pcs);
public void lockAll(Collection pcs, LockModeType mode, long timeout);
</programlisting>
<para>
Methods that do not take a lock level or timeout parameter default to the
current fetch plan. The example below demonstrates these methods in action.
</para>
<example id="ref_guide_locking_explicit">
<title>
Locking APIs
</title>
<programlisting>
import org.apache.openjpa.persistence.*;
// retrieve the lock level of an object
OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
Stock stock = ...;
LockModeType level = oem.getLockMode(stock);
if (level == OpenJPAModeType.WRITE) ...
...
oem.setOptimistic(true);
oem.getTransaction().begin();
// override default of not locking during an opt trans to lock stock object
oem.lock(stock, LockModeType.WRITE, 1000);
stock.setPrice(market.calculatePrice(stock));
oem.getTransaction().commit();
</programlisting>
</example>
</section>
<section id="ref_guide_locking_lockmgr">
<title>
Lock Manager
</title>
<indexterm zone="ref_guide_locking_lockmgr">
<primary>
locking
</primary>
<secondary>
LockManager
</secondary>
</indexterm>
<para>
<indexterm>
<primary>
LockManager
</primary>
</indexterm>
OpenJPA delegates the actual work of locking objects to the system's
<ulink url="../javadoc/org/apache/openjpa/kernel/LockManager.html"><classname>
org.apache.openjpa.kernel.LockManager</classname></ulink>. This plugin is
controlled by the <link linkend="openjpa.LockManager"><literal>
openjpa.LockManager</literal></link> configuration property. You can write your
own lock manager, or use one of the bundled options:
</para>
<itemizedlist>
<listitem>
<para>
<literal>mixed</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/MixedLockManager.html">
<classname>org.apache.openjpa.jdbc.kernel.MixedLockManager</classname>
</ulink>, which implements the JPA 2.0 specification entity locking behaviors.
It combines both the optimistic and pessimistic semantics controlled by
lock mode argument in methods define in the EntityManager
and Query interfaces or OpenJPA lock level properties.
</para>
<para>
The <literal>mixed</literal> LockManager inherits all the properties available
from <literal>version</literal> and <literal>pessimistic</literal> LockManagers.
For example: <literal>VersionCheckOnReadLock</literal> and
<literal>VersionUpdateOnWriteLock</literal> properties.
</para>
<para>
This is the default <literal>openjpa.LockManager</literal> setting in OpenJPA.
</para>
</listitem>
<listitem>
<para>
<literal>pessimistic</literal>: This is an alias for the
<ulink
url="../javadoc/org/apache/openjpa/jdbc/kernel/PessimisticLockManager.html">
<classname>org.apache.openjpa.jdbc.kernel.PessimisticLockManager</classname>
</ulink>, which
uses SELECT FOR UPDATE statements (or the database's equivalent) to lock the
database rows corresponding to locked objects. This lock
manager does not distinguish between read locks and write locks; all locks are
write locks.
</para>
<para>
The <literal>pessimistic</literal> LockManager can be configured to additionally
perform the version checking and incrementing behavior of the <literal>version
</literal> lock manager described below by setting its <literal>
VersionCheckOnReadLock</literal> and <literal>VersionUpdateOnWriteLock</literal>
properties:
</para>
<programlisting>
&lt;property name="openjpa.LockManager" value="pessimistic(VersionCheckOnReadLock=true,VersionUpdateOnWriteLock=true)"/&gt;
</programlisting>
</listitem>
<listitem>
<para>
<literal>version</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/kernel/VersionLockManager.html">
<classname>org.apache.openjpa.kernel.VersionLockManager</classname></ulink>.
This lock manager does not perform any exclusive locking, but instead ensures
read consistency by verifying that the version of all read-locked instances is
unchanged at the end of the transaction. Furthermore, a write lock will force an
increment to the version at the end of the transaction, even if the object is
not otherwise modified. This ensures read consistency with non-blocking
behavior.
</para>
</listitem>
<listitem>
<para>
<literal>none</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/kernel/NoneLockManager.html">
<classname>org.apache.openjpa.kernel.NoneLockManager</classname></ulink>, which
does not perform any locking at all.
</para>
</listitem>
</itemizedlist>
<note>
<para>
In order for the <literal>version</literal> or <literal>mixed</literal> lock
managers to prevent the dirty
read phenomenon, the underlying data store's transaction isolation level must be
set to the equivalent of "read committed" or higher.
</para>
</note>
<example id="ref_guide_locking_disable">
<title>
Disabling Locking
</title>
<programlisting>
&lt;property name="openjpa.LockManager" value="none"/&gt;
</programlisting>
</example>
</section>
<section id="ref_guide_locking_rules">
<title>
Rules for Locking Behavior
</title>
<indexterm zone="ref_guide_locking_rules">
<primary>
locking
</primary>
<secondary>
behavior
</secondary>
</indexterm>
<indexterm zone="ref_guide_locking_rules">
<primary>
lazy loading
</primary>
<secondary>
locking behavior
</secondary>
</indexterm>
<para>
Advanced persistence concepts like lazy-loading and object uniquing create
several locking corner-cases. The rules below outline OpenJPA's implicit locking
behavior in these cases.
</para>
<orderedlist>
<listitem>
<para>
When an object's state is first read within a transaction, the object is locked
at the fetch plan's current read lock level. Future reads of additional lazy
state for the object will use the same read lock level, even if the fetch plan's
level has changed.
</para>
</listitem>
<listitem>
<para>
When an object's state is first modified within a transaction, the object is
locked at the write lock level in effect when the object was first read, even if
the fetch plan's level has changed. If the object was not read previously, the
current write lock level is used.
</para>
</listitem>
<listitem>
<para>
When objects are accessed through a persistent relation field, the related
objects are loaded with the fetch plan's current lock levels, not the lock
levels of the object owning the field.
</para>
</listitem>
<listitem>
<para>
Whenever an object is accessed within a transaction, the object is re-locked at
the current read lock level. The current read and write lock levels become those
that the object "remembers" according to rules one and two above.
</para>
</listitem>
<listitem>
<para>
If you lock an object explicitly through the APIs demonstrated above, it is
re-locked at the specified level. This level also becomes both the read and
write level that the object "remembers" according to rules one and two above.
</para>
</listitem>
<listitem>
<para>
When an object is already locked at a given lock level, re-locking at a lower
level has no effect. Locks cannot be downgraded during a transaction.
</para>
</listitem>
</orderedlist>
</section>
<section id="ref_guide_locking_issues">
<title>
Known Issues and Limitations
</title>
<indexterm zone="ref_guide_locking_issues">
<primary>
locking
</primary>
<secondary>
caveats
</secondary>
</indexterm>
<para>
Due to performance concerns and database limitations, locking cannot be perfect.
You should be aware of the issues outlined in this section, as they may affect
your application.
</para>
<itemizedlist>
<listitem>
<para>
Typically, during optimistic transactions OpenJPA does not start an actual
database transaction until you flush or the optimistic transaction commits. This
allows for very long-lived transactions without consuming database resources.
When using the pessimistic lock manager, however, OpenJPA must begin a database
transaction whenever you decide to lock an object during an optimistic
transaction. This is because the pessimistic lock manager uses database locks,
and databases cannot lock rows without a transaction in progress. OpenJPA will
log an INFO message to the <literal>openjpa.Runtime</literal> logging channel
when it begins a datastore transaction just to lock an object.
</para>
</listitem>
<listitem>
<para>
In order to maintain reasonable performance levels when loading object state,
OpenJPA can only guarantee that an object is locked at the proper lock level
<emphasis>after</emphasis> the state has been retrieved from the database. This
means that it is technically possible for another transaction to "sneak in" and
modify the database record after OpenJPA retrieves the state, but before it
locks the object. The only way to positively guarantee that the object is locked
and has the most recent state to refresh the object after locking it.
</para>
<para>
When using the pessimistic lock manager, the case above can only occur when
OpenJPA cannot issue the state-loading SELECT as a locking statement due to
database limitations. For example, some databases cannot lock SELECTs that use
joins. The pessimistic lock manager will log an INFO message to the <literal>
openjpa.Runtime</literal> logging channel whenever it cannot lock the initial
SELECT due to database limitations. By paying attention to these log messages,
you can see where you might consider using an object refresh to guarantee that
you have the most recent state, or where you might rethink the way you load the
state in question to circumvent the database limitations that prevent OpenJPA
from issuing a locking SELECT in the first place.
</para>
</listitem>
<listitem>
<para>
When using the pessimistic lock manager and named queries you will see the following
<literal>WARNING</literal> message logged if you do not specify a lockMode on the named query
or you explicitly set it to <literal>LockModeType.NONE</literal>. When using the pessimistic
lock manager a <literal>LockModeType.NONE</literal> will always be promoted to <literal>LockModeType.READ</literal>.
<programlisting>
WARN [main] openjpa.MetaData - Encountered a read lock level less than LockModeType.READ when processing the NamedQuery annotation "findEmployeeById" in class "org.apache.openjpa.persistence.lockmgr.LockEmployee". Setting query lock level to LockModeType.READ.
</programlisting>
If you are using the pessimistic lock manager and you truly do want to set the lock mode to NONE for a
given query, you can use a fetch plan to do so.
<programlisting>
OpenJPAQuery q = em.createNamedQuery("findEmployeeById");
FetchPlan fp = q.getFetchPlan();
fp.setReadLockMode(LockModeType.NONE);
</programlisting>
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="ref_guide_savepoints">
<title>
Savepoints
</title>
<indexterm zone="ref_guide_savepoints">
<primary>
savepoint
</primary>
</indexterm>
<para>
Savepoints allow for fine grained control over the transactional behavior of
your application. OpenJPA's savepoint API allow you to set intermediate rollback
points in your transaction. You can then choose to rollback changes made only
after a specific savepoint, then commit or continue making new changes in the
transaction. This feature is useful for multi-stage transactions, such as
editing a set of objects over several web pages or user screens. Savepoints also
provide more flexibility to conditional transaction behavior, such as choosing to
commit or rollback a portion of the transaction based on the results of the
changes. This chapter describes how to use and configure OpenJPA savepoints.
</para>
<section id="reg_guide_savepoints_using">
<title>
Using Savepoints
</title>
<para>
OpenJPA's
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
<classname>OpenJPAEntityManager</classname></ulink> have the following
methods to control savepoint behavior. Note that the savepoints work in tandem
with the current transaction. This means that savepoints require an open
transaction, and that a rollback of the transaction will rollback all of the
changes in the transaction regardless of any savepoints set.
</para>
<programlisting>
void setSavepoint(String name);
void releaseSavepoint(String name);
void rollbackToSavepoint(String name);
</programlisting>
<para>
To set a savepoint, simply call <methodname>setSavepoint</methodname>, passing
in a symbolic savepoint name. This savepoint will define a point at which you
can preserve the state of transactional objects for the duration of the current
transaction.
</para>
<para>
Having set a named savepoint, you can rollback changes made after that point by
calling <methodname>rollbackToSavepoint</methodname>. This method will keep the
current transaction active, while restoring all transactional instances back to
their saved state. Instances that were deleted after the save point will no
longer be marked for deletion. Similarly, transient instances that were made
persistent after the savepoint will become transient again. Savepoints made
after this savepoint will be released and no longer valid, although you can
still set new savepoints. Savepoints will also be cleared after the current
transaction is committed or rolled back.
</para>
<para>
If a savepoint is no longer needed, you can release any resources it is
consuming resources by calling <methodname>releaseSavepoint</methodname>. This
method should not be called for savepoints that have been
released automatically through other means, such as commit of a transaction or
rollback to a prior savepoint. While savepoints made after this savepoint will
also be released, there are no other effects on the current transaction.
</para>
<para>
The following simple example illustrates setting, releasing, and rolling back to
a savepoint.
</para>
<example id="ref_guide_savepoints_example">
<title>
Using Savepoints
</title>
<programlisting>
import org.apache.openjpa.persistence.*;
...
OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
oem.getTransaction().begin();
Magazine mag = oem.find(Magazine.class, id);
mag.setPageCount(300);
oem.setSavepoint("pages");
mag.setPrice(mag.getPageCount() * pricePerPage);
// we decide to release "pages"...
oem.releaseSavepoint("pages");
// ... and set a new savepoint which includes all changes
oem.setSavepoint("price");
mag.setPrice(testPrice);
// we determine the test price is not good
oem.rollbackToSavepoint("price");
// had we chosen to not release "pages", we might have rolled back to
// "pages" instead
// the price is now restored to mag.getPageCount() * pricePerPage
oem.getTransaction().commit();
</programlisting>
</example>
</section>
<section id="ref_guide_savepoints_conf">
<title>
Configuring Savepoints
</title>
<para>
OpenJPA uses the
<ulink url="../javadoc/org/apache/openjpa/kernel/SavepointManager">
<classname>org.apache.openjpa.kernel.SavepointManager</classname></ulink>
<link linkend="ref_guide_conf_plugins">plugin</link> to handle preserving the
savepoint state. OpenJPA includes the following <classname>SavepointManager
</classname> plugins:
</para>
<itemizedlist>
<listitem>
<para>
<literal>in-mem</literal>: The default. This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/kernel/InMemorySavepointManager.html"><classname>
org.apache.openjpa.kernel.InMemorySavepointManager</classname></ulink>. This
plugin stores all state, including field values, in memory. Due to this
behavior, each set savepoint is designed for small to medium transactional
object counts.
</para>
</listitem>
<listitem>
<para>
<literal>jdbc</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/JDBC3SavepointManager.html"><classname>
org.apache.openjpa.jdbc.kernel.JDBC3SavepointManager</classname></ulink>. This
plugin requires <literal>JDBC 3</literal> and <classname> java.sql.Savepoint
</classname> support to operate. Note that this plugin implements savepoints by
issuing a flush to the database.
</para>
</listitem>
</itemizedlist>
</section>
</section>
<!--
<section id="ref_guide_enterprise_queryext">
<title>
Query Language Extensions
</title>
<indexterm zone="ref_guide_enterprise_queryext">
<primary>
Query
</primary>
<secondary>
language extensions
</secondary>
<seealso>
JPQL
</seealso>
</indexterm>
<para>
JPQL is a powerful, easy-to-use query language, but you may occasionally find it
limiting in some way. To circumvent the limitations of JPQL, OpenJPA provides
extensions to the JPQL language, and allows you to extend it as well.
</para>
<warning>
<para>
The JPQL parser in this release does not yet allow extensions. They will be made
available to JPQL users in a future release.
</para>
</warning>
<section id="ref_guide_enterprise_queryext_jdoql">
<title>
Filter Extensions
</title>
<indexterm zone="ref_guide_enterprise_queryext_jdoql">
<primary>
JPQL
</primary>
<secondary>
language extension
</secondary>
</indexterm>
<para>
Filter extensions are custom methods that you can use in your query filter,
having, ordering, and result strings. OpenJPA provides some built-in filter
extensions, and you can develop your own custom extensions as needed. You can
optionally preface all filter extensions with <literal>ext:</literal> in your
query string. For example, the following example uses a hypothetical <literal>
firstThreeChars</literal> extension to search for cities whose name begins with
the 3 characters 'H', 'a', 'r'.
</para>
<example id="ref_guide_enterprise_queryext_jdoql_ext">
<title>
Basic Filter Extension
</title>
<programlisting>
Query q = em.createQuery("select c from City c where c.name.ext:firstThreeChars () = 'Har'");
List results = q.getResultList();
</programlisting>
</example>
<para>
Note that it is perfectly OK to chain together extensions. For example, let's
modify our search above to be case-insensitive using another hypothetical
extension, <literal>equalsIgnoreCase</literal>:
</para>
<example id="ref_guide_enterprise_queryext_jdoql_chain">
<title>
Chaining Filter Extensions
</title>
<programlisting>
Query query = em.createQuery("select c from City c where "
+ "c.name.ext:firstThreeChars ().ext:equalsIgnoreCase ('Har')");
List results = q.getResultList();
</programlisting>
</example>
<para>
Finally, when using filter extensions you must be aware that any SQL-specific
extensions can only execute against the database, and cannot be used for
in-memory queries (recall that OpenJPA executes queries in-memory when you
supply a candidate collection rather than a class, or when you set the <literal>
IgnoreChanges</literal> and <literal>FlushBeforeQueries</literal> properties to
<literal>false</literal> and you execute a query within a transaction in which
you've modified data that may affect the results).
</para>
<section id="ref_guide_enterprise_queryext_jdoql_included">
<title>
Included Filter Extensions
</title>
<para>
OpenJPA includes two default filter extensions to enhance the power of your
queries.
</para>
<itemizedlist>
<listitem>
<para>
<indexterm>
<primary>
JPQL
</primary>
<secondary>
language extension
</secondary>
<tertiary>
getColumn
</tertiary>
</indexterm>
<literal>getColumn</literal>: Places the proper alias for the given column name
into the SELECT statement that is issued. This extension cannot be used for
in-memory queries. When traversing relations, the column is assumed to be in the
primary table of the related type.
</para>
<programlisting>
select e from Employee e where e.company.address.ext:getColumn ('ID') = 5
</programlisting>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
JPQL
</primary>
<secondary>
language extension
</secondary>
<tertiary>
sql
</tertiary>
</indexterm>
<literal>sql</literal>: Embeds the given SQL argument into the SELECT
statement. This extension cannot be used for in-memory queries.
</para>
<programlisting>
select p from Product p where p.price &lt; ext:sql ('(SELECT AVG(PRICE) FROM PRODUCTS)')
</programlisting>
</listitem>
</itemizedlist>
</section>
<section id="ref_guide_enterprise_queryext_jdoql_custom">
<title>
Developing Custom Filter Extensions
</title>
<indexterm zone="ref_guide_enterprise_queryext_jdoql_custom">
<primary>
JPQL
</primary>
<secondary>
language extension
</secondary>
<tertiary>
custom
</tertiary>
</indexterm>
<para>
You can write your own extensions by implementing the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/exps/JDBCFilterListener.html">
<classname>org.apache.openjpa.jdbc.kernel.exps.JDBCFilterListener</classname>
</ulink> interface. View the Javadoc documentation for details. Additionally,
the source for all of OpenJPA's built-in query extensions is included in your
OpenJPA download to get you started. The built-in extensions reside in the
<filename> src/openjpa/kernel/exps</filename> and <filename>
src/openjpa/jdbc/kernel/exps</filename> directories of your distribution.
</para>
</section>
<section id="ref_guide_enterprise_queryext_jdoql_conf">
<title>
Configuring Filter Extensions
</title>
<indexterm zone="ref_guide_enterprise_queryext_jdoql_conf">
<primary>
JPQL
</primary>
<secondary>
language extension
</secondary>
<tertiary>
configuration
</tertiary>
</indexterm>
<para>
There are two ways to register your custom filter extensions with OpenJPA:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>Registration by properties:</emphasis> You can register custom filter
extensions by setting the <link linkend="openjpa.FilterListeners"><literal>
openjpa.FilterListeners</literal></link> configuration property to a
comma-separated list of plugin strings (see
<xref linkend="ref_guide_conf_plugins"/>) describing your extensions
classes. Extensions registered in this fashion must have a public no-arg
constructor. They must also be thread safe, because they will be shared across
all queries.
</para>
</listitem>
<listitem>
<para>
<emphasis>Per-query registration:</emphasis> You can register filter extensions
for an individual <classname>Query</classname> through the <methodname>
OpenJPAQuery.addFilterListener</methodname> method. You might use per-query
registration for very specific extensions that do not apply globally.
</para>
<para>
See the <classname>OpenJPAQuery</classname>
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAQuery.html">
Javadoc</ulink> for details.
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="ref_guide_aggregates_custom">
<title>
Aggregate Extensions
</title>
<indexterm zone="ref_guide_aggregates_custom">
<primary>
JPQL
</primary>
<secondary>
aggregate extension
</secondary>
</indexterm>
<para>
Just as you can write your own filter methods, you can write your own query
aggregates by implementing the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/exps/JDBCAggregateListener.html">
<classname>org.apache.openjpa.jdbc.kernel.exps.JDBCAggregateListener</classname>
</ulink> interface. View the Javadoc documentation for details. When using your
custom aggregates in result or having query clauses, you can optionally prefix
the function name with <literal>ext:</literal> to identify it as an extension.
</para>
<section id="ref_guide_aggregates_conf">
<title>
Configuring Query Aggregates
</title>
<indexterm zone="ref_guide_aggregates_conf">
<primary>
JPQL
</primary>
<secondary>
aggregate extension
</secondary>
<tertiary>
configuration
</tertiary>
</indexterm>
<para>
There are two ways to register your custom query aggregates with OpenJPA:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>Registration by properties:</emphasis> You can register custom query
aggregates by setting the <link linkend="openjpa.AggregateListeners"><literal>
openjpa.AggregateListeners</literal></link> configuration property to a
comma-separated list of plugin strings (see
<xref linkend="ref_guide_conf_plugins"/>) describing your aggregate
implementation. Aggregates registered in this fashion must have a public no-arg
constructor. They must also be thread safe, because they will be shared across
all queries.
</para>
</listitem>
<listitem>
<para>
<emphasis>Per-query registration:</emphasis> You can register query aggregates
for an individual <classname>Query</classname> through the <methodname>
OpenJPAQuery.addAggregateListener</methodname> method. You might use per-query
registration for very specific aggregates that do not apply globally.
</para>
<para>
See the <classname>OpenJPAQuery</classname>
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAQuery.html">
Javadoc</ulink> for details.
</para>
</listitem>
</itemizedlist>
</section>
</section>
-->
<section id="ref_guide_enterprise_methodql">
<title>
MethodQL
</title>
<indexterm zone="ref_guide_enterprise_methodql">
<primary>
MethodQL
</primary>
</indexterm>
<indexterm>
<primary>
Query
</primary>
<secondary>
MethodQL
</secondary>
<see>
MethodQL
</see>
</indexterm>
<para>
If JPQL and SQL queries do not match your needs, OpenJPA also allows you to name
a Java method to use to load a set of objects. In a <emphasis>MethodQL
</emphasis> query, the query string names a static method to invoke to determine
the matching objects:
</para>
<programlisting>
import org.apache.openjpa.persistence.*;
...
// the method query language is 'openjpa.MethodQL'.
// set the query string to the target method to execute, prefixed by fullly-
// qualified class name.
// If a candidate class has been specified for the query, then if the class is
// in the candidate class' package or in the query imports, you can omit the
// package. If the method is in the candidate class, you can omit the class name
// and just specify the method name.
OpenJPAEntityManager oem = OpenJPAPersistence.cast(emf);
OpenJPAQuery q = oem.createQuery("openjpa.MethodQL", "com.xyz.Finder.getByName");
// parameters are passed the same way as in standard queries
// but you have to declare the parameters with their types on the implementation
// Unwrap the implementation and declare parameters with types in a
// comma-separated list
q.unwrap(org.apache.openjpa.kernel.Query.class)
.declareParameters("String firstName, String lastName");
q.setParameter("firstName", "Fred").setParameter("lastName", "Lucas");
// this executes the target method to get the results
List results = q.getResultList();
// The result is returned as a list but the element(s) in the list is determined
// by the returned value of the target method
</programlisting>
<para>
For datastore queries, the method must have the following signature:
</para>
<programlisting>
public static <ulink url="../javadoc/org/apache/openjpa/lib/rop/ResultObjectProvider.html">ResultObjectProvider</ulink> xxx(<ulink url="../javadoc/org/apache/openjpa/kernel/StoreContext.html">StoreContext</ulink> ctx, <ulink url="../javadoc/org/apache/openjpa/meta/ClassMetaData.html">ClassMetaData</ulink> meta, boolean subclasses, Map params, <ulink url="../javadoc/org/apache/openjpa/kernel/FetchConfiguration.html">FetchConfiguration </ulink> fetch)
</programlisting>
<para>
The returned result object provider should produce objects of the candidate
class that match the method's search criteria. If the returned objects do not
have all fields in the given fetch configuration loaded, OpenJPA will make
additional trips to the datastore as necessary to fill in the data for the
missing fields.
</para>
<para>
In-memory execution is slightly different, taking in one object at a time and
returning a boolean on whether the object matches the query:
</para>
<programlisting>
public static boolean xxx(<ulink url="../javadoc/org/apache/openjpa/kernel/StoreContext.html">StoreContext</ulink> ctx, <ulink url="../javadoc/org/apache/openjpa/meta/ClassMetaData.html">ClassMetaData</ulink> meta, boolean subclasses, Object obj, Map params, <ulink url="../javadoc/org/apache/openjpa/kernel/FetchConfiguration.html">FetchConfiguration</ulink> fetch)
</programlisting>
<para>
In both method versions, the given <literal>params</literal> map contains the
names and values of all the parameters for the query.
</para>
</section>
<!--
</section>
-->
<section id="ref_guide_sequence">
<title>
Generators
</title>
<indexterm zone="ref_guide_sequence">
<primary>
generators
</primary>
<secondary>
Seq interface
</secondary>
</indexterm>
<para>
The JPA Overview's <xref linkend="jpa_overview_mapping"/> details using
generators to automatically populate identity fields in JPA.
</para>
<para>
OpenJPA represents all generators internally with the
<ulink url="../javadoc/org/apache/openjpa/kernel/Seq.html"><classname>
org.apache.openjpa.kernel.Seq</classname></ulink> interface. This interface
supplies all the context you need to create your own custom generators,
including the current persistence environment, the JDBC <classname>DataSource
</classname>, and other essentials. The
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.html">
<classname>org.apache.openjpa.jdbc.kernel.AbstractJDBCSeq</classname></ulink>
helps you create custom JDBC-based sequences. OpenJPA also supplies the
following built-in <classname>Seq</classname>s:
</para>
<itemizedlist>
<listitem>
<para>
<indexterm>
<primary>
generators
</primary>
<secondary>
table
</secondary>
</indexterm>
<literal>table</literal>: This is OpenJPA's default implementation. It is an
alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.html">
<classname>org.apache.openjpa.jdbc.kernel.TableJDBCSeq</classname></ulink>
class. The <classname>TableJDBCSeq</classname> uses a special single-row table
to store a global sequence number. If the table does not already exist, it is
created the first time you run the
<link linkend="ref_guide_mapping_mappingtool">mapping tool</link> on a class
that requires it. You can also use the class's <methodname>main</methodname>
method to manipulate the table; see the
<methodname>TableJDBCSeq.main</methodname> method Javadoc for usage details.
</para>
<para>
This <classname>Seq</classname> has the following properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>Table</literal>: The name of the sequence number table to use.
Defaults to <literal>OPENJPA_SEQUENCE_TABLE</literal>. If the entities are
mapped to the same table name but with different schema name within one
PersistenceUnit, one <literal>OPENJPA_SEQUENCE_TABLE</literal> is created
for each schema.
</para>
</listitem>
<listitem>
<para>
<literal>PrimaryKeyColumn</literal>: The name of the primary key column for the
sequence table. Defaults to <literal>ID</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>SequenceColumn</literal>: The name of the column that will hold the
current sequence value. Defaults to <literal>SEQUENCE_VALUE</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>Allocate</literal>: The number of values to allocate on each database
trip. Defaults to 50, meaning the class will set aside the next 50 numbers each
time it accesses the sequence table, which in turn means it only has to make a
database trip to get new sequence numbers once every 50 sequence number
requests.
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
generators
</primary>
<secondary>
class-table
</secondary>
</indexterm>
<literal>class-table</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.html">
<classname>org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq</classname></ulink>
. This <classname>Seq</classname> is like the <classname>TableJDBCSeq
</classname> above, but maintains a separate table row, and therefore a separate
sequence number, for each base persistent class. It has all the properties of
the <classname>TableJDBCSeq</classname>. Its table name defaults to <literal>
OPENJPA_SEQUENCES_TABLE</literal>. It also adds the following properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>IgnoreUnmapped</literal>: Whether to ignore unmapped base classes, and
instead use one row per least-derived mapped class. Defaults to <literal>
false</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>UseAliases</literal>: Whether to use each class' entity name as the
primary key value of each row, rather than the full class name. Defaults to
<literal>false</literal>.
</para>
</listitem>
</itemizedlist>
<para>
As with the <classname>TableJDBCSeq</classname>, the <classname>
ClassTableJDBCSeq</classname> creates its table automatically during mapping
tool runs. However, you can manually manipulate the table through the class'
<methodname>main</methodname> method. See the Javadoc for the
<methodname> ClassTableJDBCSeq.main</methodname> method for usage details.
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
generators
</primary>
<secondary>
value-table
</secondary>
</indexterm>
<literal>value-table</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/ValueTableJDBCSeq.html">
<classname>org.apache.openjpa.jdbc.kernel.ValueTableJDBCSeq</classname></ulink>
. This <classname>Seq</classname> is like the <classname>ClassTableJDBCSeq
</classname> above, but has an arbitrary number of rows for sequence values,
rather than a fixed pattern of one row per class. Its table defaults to
<literal>OPENJPA_SEQUENCES_TABLE</literal>. It has all the properties of the
<classname>TableJDBCSeq</classname>, plus:
</para>
<itemizedlist>
<listitem>
<para>
<literal>PrimaryKeyValue</literal>: The primary key value used by this instance.
</para>
</listitem>
</itemizedlist>
<para>
As with the <classname>TableJDBCSeq</classname>, the <classname>
ValueTableJDBCSeq</classname> creates its table automatically during mapping
tool runs. However, you can manually manipulate the table through the class'
<methodname>main</methodname> method. See the Javadoc for the
<methodname>ValueTableJDBCSeq.main</methodname> method for usage details.
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
generators
</primary>
<secondary>
native
</secondary>
</indexterm>
<literal>native</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.html">
<classname>org.apache.openjpa.jdbc.kernel.NativeJDBCSeq</classname></ulink>.
Many databases have a concept of "native sequences" - a built-in mechanism for
obtaining incrementing numbers. For example, in Oracle database, you can create a
database sequence with a statement like <literal>CREATE SEQUENCE MYSEQUENCE
</literal>. Sequence values can then be atomically obtained and incremented
with the statement <literal>SELECT MYSEQUENCE.NEXTVAL FROM DUAL</literal>.
OpenJPA provides support for this common mechanism of sequence generation with
the <classname> NativeJDBCSeq</classname>, which accepts the following
properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>Sequence</literal>: The name of the database sequence. Defaults to
<literal>OPENJPA_SEQUENCE</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>InitialValue</literal>: The initial sequence value. Defaults to 1.
</para>
</listitem>
<listitem>
<para>
<literal>Increment</literal>: The amount the sequence increments. Defaults to 1.
</para>
</listitem>
<listitem>
<para>
<literal>Allocate</literal>: The number of values to allocate on each database
trip. Defaults to 50, meaning the class will set aside the next 50 numbers each
time it accesses the sequence, which in turn means it only has to make a
database trip to get new sequence numbers once every 50 sequence number
requests.
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
<indexterm>
<primary>
generators
</primary>
<secondary>
time
</secondary>
</indexterm>
<literal>time</literal>: This is an alias for the
<ulink url="../javadoc/org/apache/openjpa/kernel/TimeSeededSeq.html">
<classname>org.apache.openjpa.kernel.TimeSeededSeq</classname></ulink>. This
type uses an in-memory static counter, initialized to the current time in
milliseconds and monotonically incremented for each value requested. It is only
suitable for single-JVM environments.
</para>
</listitem>
</itemizedlist>
<para>
You can use JPA <literal>SequenceGenerator</literal>s to describe any built-in
<classname>Seq</classname>s or your own <classname>Seq</classname>
implementation. Set the <literal>sequenceName</literal> attribute to a plugin
string describing your choice.
</para>
<blockquote>
<para>
If specifying your own class name, you must include parentheses at the end of
the class name, even if you have no plugin properties to configure.
(E.g., <literal>sequenceName="com.example.SeqImpl()"</literal>.
</para>
</blockquote>
<para>
See <xref linkend="jpa_overview_mapping_sequence"/> in the JPA Overview for
details on defining <literal>SequenceGenerator</literal>s.
</para>
<para>
See <xref linkend="ref_guide_conf_plugins"/> for plugin string formatting.
</para>
<example id="ref_guide_sequence_named">
<title>
Named Seq Sequence
</title>
<programlisting>
@Entity
@Table(name="AUTO")
public class Author {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="AuthorSeq")
@SequenceGenerator(name="AuthorSeq", sequenceName="table(Table=AUTO_SEQ)", allocationSize=100)
@Column(name="AID")
private long id;
...
}
</programlisting>
<para>
Note that if you want to use a plugin string without any arguments, you must
still suffix the plugin type with <literal>()</literal> to differentiate it from
a sequence name in the <literal>SequenceGenerator.sequenceName</literal> attribute:
</para>
<programlisting>
@SequenceGenerator(name="AuthorSeq", sequenceName="table()")
</programlisting>
</example>
<para>
<!-- OPENJPA-1343: It seems that this only works with the time and
sjvm aliases. This due to an issue that was brought up in OPENJPA-1642
Custom sequences may or may not work depending on their nature.-->
OpenJPA maintains a <emphasis>system</emphasis> sequence to generate datastore
identity values for classes that do not declare a specific datastore identity
strategy. You can configure the system sequence through the
<link linkend="openjpa.Sequence"><literal>openjpa.Sequence</literal></link>
configuration property. This property accepts a plugin string describing a
<classname>Seq</classname> instance.
</para>
<example id="ref_guide_sequence_systemex">
<title>
System Sequence Configuration
</title>
<programlisting>
&lt;property name="openjpa.Sequence" value="time(Increment=100)"/&gt;
</programlisting>
</example>
<para>
In JPA, set your <literal>GeneratedValue</literal> annotation's <literal>
strategy</literal> attribute to <literal>AUTO</literal> to use the configured
system sequence. Or, because <literal>AUTO</literal> is the default strategy,
use the annotation without attributes:
</para>
<programlisting>
@GeneratedValue
private long id;
</programlisting>
<section id="ref_guide_sequence_runtime">
<title>
Runtime Access
</title>
<indexterm zone="ref_guide_sequence_runtime">
<primary>
Sequence
</primary>
<secondary>
runtime access
</secondary>
</indexterm>
<para>
OpenJPA allows you to access named generators at runtime through the
<methodname>OpenJPAEntityManager.getNamedGenerator</methodname> method:
</para>
<programlisting>
public Generator getNamedGenerator(String name);
</programlisting>
<para>
The returned
<ulink url="../javadoc/org/apache/openjpa/persistence/Generator.html">
<classname>org.apache.openjpa.persistence.Generator</classname></ulink> is a
facade over an internal OpenJPA <classname>Seq</classname>.
</para>
<para>
The <classname>OpenJPAEntityManager</classname> includes additional APIs to
retrieve the identity generator of any class, or the generator of any field.
With these APIs, you do not have to know the generator name. Additionally, they
allow you to access the implicit generator used by default for datastore
identity classes. See the
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
Javadoc</ulink> for the <methodname> OpenJPAEntityManager.getIdentityGenerator
</methodname> and <methodname>OpenJPAEntityManager.getFieldGenerator
</methodname> methods for API details.
</para>
</section>
</section>
<section id="ref_guide_runtime_pm_event">
<title>
Transaction Events
</title>
<indexterm zone="ref_guide_runtime_pm_event">
<primary>
transactions
</primary>
<secondary>
events
</secondary>
</indexterm>
<para>
The OpenJPA runtime supports broadcasting transaction-related events. By
registering one or more
<ulink url="../javadoc/org/apache/openjpa/event/TransactionListener.html">
<classname>org.apache.openjpa.event.TransactionListener</classname></ulink> s,
you can receive notifications when transactions begin, flush, rollback, commit,
and more. Where appropriate, event notifications include the set of
persistence-capable objects participating in the transaction.
</para>
<programlisting>
public void addTransactionListener(Object listener);
public void removeTransactionListener(Object listener);
</programlisting>
<para>
These <classname>OpenJPAEntityManagerSPI</classname> methods allow you to add
and remove listeners. These methods are outside the bounds of the published OpenJPA APIs, and are subject to change in the future.
</para>
<para>
For details on the transaction framework, see the <literal>
org.apache.openjpa.event</literal> package
<ulink url="../javadoc/org/apache/openjpa/event/package-summary.html">Javadoc</ulink>.
Also see <xref linkend="ref_guide_event"/> for a description of OpenJPA's
remote event support.
</para>
</section>
<section id="ref_guide_enterprise_abstractstore">
<title>
Non-Relational Stores
</title>
<para>
It is possible to adapt OpenJPA to access a non-relational datastore by creating
an implementation of the
<ulink url="../javadoc/org/apache/openjpa/kernel/StoreManager.html"><literal>
org.apache.openjpa.kernel.StoreManager</literal></ulink> interface. OpenJPA
provides an abstract <literal>StoreManager</literal> implementation to
facilitate this process. See the <literal>org.apache.openjpa.abstractstore
</literal> package <ulink url="../javadoc/org/apache/openjpa/abstractstore/package-summary.html">
Javadoc</ulink> for details.
</para>
</section>
</chapter>