| <?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>jakarta.persistence.EntityManagerFactory</classname>: <emphasis> |
| <classname>org.apache.openjpa.kernel.BrokerFactory</classname></emphasis> |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <classname>jakarta.persistence.EntityManager</classname>: <emphasis><classname> |
| org.apache.openjpa.kernel.Broker</classname></emphasis> |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <classname>jakarta.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> |
| <property name="openjpa.BrokerImpl" value="EvictFromDataCache=true"/> |
| </programlisting> |
| </example> |
| <para> |
| Additionally, some advanced users may want to add capabilities to OpenJPA's |
| internal <ulink url="../../apidocs/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="../../apidocs/org/apache/openjpa/kernel/BrokerImpl.html"> |
| <classname>org.apache.openjpa.kernel.BrokerImpl</classname></ulink> and |
| <ulink url="../../apidocs/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> |
| jakarta.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="../../apidocs/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="../../apidocs/org/apache/openjpa/persistence/OpenJPAEntityManager.html"> |
| <classname>org.apache.openjpa.persistence.OpenJPAEntityManager</classname> |
| </ulink> interface. This interface extends the standard <classname> |
| jakarta.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="../../apidocs/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="../../apidocs/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<Magazine> 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 |
| jakarta.persistence.Cache interface. OpenJPA provides further extensions via |
| the org.apache.openjpa.persistence.StoreCache interface documented at |
| <ulink url="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/org/apache/openjpa/persistence/OpenJPAEntityTransaction.html"> |
| <classname>org.apache.openjpa.persistence.OpenJPAEntityTransaction</classname></ulink> |
| extends <classname>jakarta.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="../../apidocs/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>jakarta.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> |
| <property name="openjpa.ReadLockLevel" value="none"/> |
| <property name="openjpa.WriteLockLevel" value="write"/> |
| <property name="openjpa.LockTimeout" value="30000"/> |
| </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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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> |
| <property name="openjpa.LockManager" value="pessimistic(VersionCheckOnReadLock=true,VersionUpdateOnWriteLock=true)"/> |
| </programlisting> |
| </listitem> |
| <listitem> |
| <para> |
| <literal>version</literal>: This is an alias for the |
| <ulink url="../../apidocs/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="../../apidocs/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> |
| <property name="openjpa.LockManager" value="none"/> |
| </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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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 < 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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/org/apache/openjpa/lib/rop/ResultObjectProvider.html">ResultObjectProvider</ulink> xxx(<ulink url="../../apidocs/org/apache/openjpa/kernel/StoreContext.html">StoreContext</ulink> ctx, <ulink url="../../apidocs/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="../../apidocs/org/apache/openjpa/kernel/StoreContext.html">StoreContext</ulink> ctx, <ulink url="../../apidocs/org/apache/openjpa/meta/ClassMetaData.html">ClassMetaData</ulink> meta, boolean subclasses, Object obj, Map params, <ulink url="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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> |
| <property name="openjpa.Sequence" value="time(Increment=100)"/> |
| </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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/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="../../apidocs/org/apache/openjpa/abstractstore/package-summary.html"> |
| Javadoc</ulink> for details. |
| </para> |
| </section> |
| </chapter> |