| <?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_caching"> |
| <title> |
| Caching |
| </title> |
| <para> |
| OpenJPA utilizes several configurable caches to maximize performance. This |
| chapter explores OpenJPA's data cache, query cache, and query compilation cache. |
| </para> |
| <section id="ref_guide_cache"> |
| <title> |
| Data Cache |
| </title> |
| <indexterm zone="ref_guide_cache"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| data cache |
| </secondary> |
| </indexterm> |
| <para> |
| The OpenJPA data cache is an optional cache of persistent object data that |
| operates at the <classname>EntityManagerFactory</classname> level. This cache is |
| designed to significantly increase performance while remaining in full |
| compliance with the JPA standard. This means that turning on the caching option |
| can transparently increase the performance of your application, with no changes |
| to your code. |
| </para> |
| <para> |
| OpenJPA's data cache is not related to the <classname>EntityManager</classname> |
| cache dictated by the JPA specification. The JPA specification mandates behavior |
| for the <classname>EntityManager</classname> cache aimed at guaranteeing |
| transaction isolation when operating on persistent objects. |
| </para> |
| <para> |
| OpenJPA's data cache is designed to provide significant performance increases |
| over cacheless operation, while guaranteeing that behavior will be identical in |
| both cache-enabled and cacheless operation. |
| </para> |
| <para> |
| There are five ways to access data via the OpenJPA APIs: standard relation |
| traversal, large result set relation traversal, queries, looking up an object by |
| id, and iteration over an <classname>Extent</classname>. OpenJPA's cache plugin |
| accelerates three of these mechanisms. It does not provide any caching of large |
| result set relations or <classname>Extent</classname> iterators. If you find |
| yourself in need of higher-performance <classname>Extent</classname> iteration, |
| see <xref linkend="ref_guide_cache_limits_extent"/>. |
| </para> |
| <table> |
| <title> |
| Data access methods |
| </title> |
| <tgroup cols="2" align="left" colsep="1" rowsep="1"> |
| <colspec colname="access-method"/><colspec colname="cacheable"/> |
| <thead> |
| <row> |
| <entry colname="access-method">Access method</entry> |
| <entry colname="cacheable">Uses cache</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry colname="access-method"> |
| Standard relation traversal |
| </entry> |
| <entry colname="cacheable"> |
| Yes |
| </entry> |
| </row> |
| <row> |
| <entry colname="access-method"> |
| Large result set relation traversal |
| </entry> |
| <entry colname="cacheable">No</entry> |
| </row> |
| <row> |
| <entry colname="access-method">Query</entry> |
| <entry colname="cacheable">Yes</entry> |
| </row> |
| <row> |
| <entry colname="access-method"> |
| Lookups by object id |
| </entry> |
| <entry colname="cacheable">Yes</entry> |
| </row> |
| <row> |
| <entry colname="access-method"> |
| Iteration over an <classname>Extent</classname> |
| </entry> |
| <entry colname="cacheable">No</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| <para> |
| When enabled, the cache is checked before making a trip to the datastore. Data |
| is stored in the cache when objects are committed and when persistent objects |
| are loaded from the datastore. |
| </para> |
| <para> |
| OpenJPA's data cache can operate in both single-JVM and multi-JVM environments. |
| Multi-JVM caching is achieved through the use of the distributed event |
| notification framework described in <xref linkend="ref_guide_event"/>, or |
| through custom integrations with a third-party distributed cache. |
| </para> |
| <para> |
| The single JVM mode of operation maintains and shares a data cache across all |
| <classname>EntityManager</classname> instances obtained from a particular |
| <classname>EntityManagerFactory</classname>. This is not appropriate for use in |
| a distributed environment, as caches in different JVMs or created from different |
| <classname>EntityManagerFactory</classname> objects will not be synchronized. |
| </para> |
| <section id="ref_guide_cache_conf"> |
| <title> |
| Data Cache Configuration |
| </title> |
| <para> |
| There are two ways to enable the basic single-factory cache. One is using |
| <link linkend="openjpa.DataCache"><literal>openjpa.DataCache</literal></link> |
| property, the other is using JPA standard shared-cache-mode element or the |
| jakarta.persistence.sharedCache.mode property. |
| </para> |
| <section id="ref_guide_data_cache"> |
| <title> |
| openjpa.DataCache Configuration |
| </title> |
| <para> |
| To enable the basic single-factory cache set the |
| <link linkend="openjpa.DataCache"><literal>openjpa.DataCache</literal></link> |
| property to <literal>true</literal>: |
| </para> |
| <example id="ref_guide_cache_conf_sjvm"> |
| <title> |
| Single-JVM Data Cache |
| </title> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true"/> |
| </programlisting> |
| </example> |
| <para> |
| To configure the data cache to remain up-to-date in a distributed environment, |
| set the <link linkend="openjpa.RemoteCommitProvider"><literal> |
| openjpa.RemoteCommitProvider</literal></link> property appropriately, or |
| integrate OpenJPA with a third-party caching solution. Remote commit providers |
| are described in <xref linkend="ref_guide_event"/>. |
| </para> |
| <para> |
| <indexterm> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| size |
| </secondary> |
| </indexterm> |
| OpenJPA's default implementation maintains a map of object |
| ids to cache data. By default, 1000 elements are kept in cache. When the cache |
| overflows, random entries are evicted. The maximum cache size can be |
| adjusted by setting the <literal>CacheSize</literal> property in your plugin |
| string - see below for an example. Objects that are pinned into the cache are |
| not counted when determining if the cache size exceeds its maximum size. |
| </para> |
| <para> |
| Expired objects are moved to a soft reference map, so they may stick around for |
| a little while longer. You can control the number of soft references OpenJPA |
| keeps with the <literal>SoftReferenceSize</literal> property. Soft references |
| are unlimited by default. Set to 0 to disable soft references completely. |
| </para> |
| <para> |
| Both the QueryCache and DataCache can be configured to use a backing <literal>Lru</literal> map rather than the default |
| concurrent HashMap. Note that enabling the <literal>Lru</literal> cache can hurt performance as this map in not as |
| scalable as the default map. |
| </para> |
| <example id="ref_guide_cache_conf_lru"> |
| <title> |
| Lru Cache |
| </title> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(Lru=true)"/> |
| <property name="openjpa.QueryCache" value="true(Lru=true)"/> |
| </programlisting> |
| </example> |
| <example id="ref_guide_cache_conf_size"> |
| <title> |
| Data Cache Size |
| </title> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(CacheSize=5000, SoftReferenceSize=0)"/> |
| </programlisting> |
| </example> |
| <para> |
| <indexterm> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| timeout |
| </secondary> |
| </indexterm> |
| You can specify a cache timeout value for a class by setting the timeout |
| <link linkend="ref_guide_meta_ext">metadata extension</link> to the amount of |
| time in milliseconds a class's data is valid. Use a value of -1 for no |
| expiration. This is the default value. |
| </para> |
| <example id="ex_timeout_cache"> |
| <title> |
| Data Cache Timeout |
| </title> |
| <para> |
| Timeout <classname>Employee</classname> objects after 10 seconds. |
| </para> |
| <programlisting> |
| @Entity |
| @DataCache(timeout=10000) |
| public class Employee { |
| ... |
| } |
| </programlisting> |
| </example> |
| |
| <para> |
| <indexterm> |
| <primary>caching</primary> |
| <secondary>exclusions</secondary> |
| </indexterm> |
| Entities may be explicitly excluded from the cache by providing a |
| list of fully qualified class names in the <literal>ExcludedTypes</literal> argument. |
| The entities provided via <literal>ExcludedTypes</literal> will not be cached |
| regardless of the <classname>DataCache</classname> annotation. |
| </para> |
| <example id="ex_exclude_types_from_cache"> |
| <title> |
| Excluding entities |
| </title> |
| <para> |
| Exclude entities <classname>foo.bar.Person</classname> and |
| <classname>foo.bar.Employee</classname> from the cache. |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(ExcludedTypes=foo.bar.Person;foo.bar.Employee)"/> |
| </programlisting> |
| </para> |
| </example> |
| |
| <para> |
| <indexterm> |
| <primary>caching</primary> |
| <secondary>inclusions</secondary> |
| </indexterm> |
| Entities may be explicitly included in the cache by providing a |
| list of fully qualified class names in the <literal>Types</literal> argument. |
| Any entities which are not included |
| in this list will not be cached. |
| </para> |
| <example id="ex_include_types_in_cache"> |
| <title> |
| Including entities |
| </title> |
| <para> |
| Include only entity <classname>foo.bar.FullTimeEmployee</classname> in the cache. |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(Types=foo.bar.FullTimeEmployee)"/> |
| </programlisting> |
| </para> |
| </example> |
| <para> |
| See the <ulink url="../../apidocs/org/apache/openjpa/persistence/DataCache.html"> |
| <classname>org.apache.openjpa.persistence.DataCache</classname></ulink> Javadoc |
| for more information on the <classname>DataCache</classname> annotation. |
| </para> |
| <para> |
| <indexterm> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| cron-style invalidation |
| </secondary> |
| </indexterm> |
| A cache can specify that it should be cleared at certain times rather than using |
| data timeouts. The <literal>EvictionSchedule</literal> property of OpenJPA's |
| cache implementation can be input in two different formats. The first is a <literal>cron</literal> style eviction schedule. |
| The format of this property is a whitespace-separated list of five tokens, where |
| the <literal>*</literal> symbol (asterisk), indicates match all. The tokens are, |
| in order: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Minute |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Hour of Day |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Day of Month |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Month |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Day of Week |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| For example, the following <literal>openjpa.DataCache</literal> setting |
| schedules the default cache to evict values from the cache at 15 and 45 minutes |
| past 3 PM on Sunday. |
| </para> |
| <programlisting> |
| true(EvictionSchedule='15,45 15 * * 1') |
| </programlisting> |
| <para> |
| The second format for this property is an interval style eviction schedule. The |
| format of this property is a <literal>+</literal> followed by the number of minutes |
| between each time that the cache should be evicted. |
| </para> |
| <para> |
| For example, the following <literal>openjpa.DataCache</literal> setting schedules the default cache |
| to evict values from the cache every 120 minutes. |
| </para> |
| <para> |
| <programlisting> |
| true(EvictionSchedule='+120') |
| </programlisting> |
| </para> |
| <example id="bulk_update_evict_cache"> |
| <title> |
| Bulk updates and cache eviction |
| </title> |
| <para> |
| Setting <literal>EvictOnBulkUpdate</literal> to <literal>false</literal> will tell OpenJPA to not evict from the DataCache when executing |
| an UPDATE or DELETE statement. The default for the value is <literal>true</literal>. |
| </para> |
| <para> |
| <programlisting><property name="openjpa.DataCache" value="true(EvictOnBulkUpdate=false)"/></programlisting> |
| </para> |
| </example> |
| </section> |
| <section id="ref_guide_shared_cache_mode_integration"> |
| <title> |
| Integration with JPA standard shared cache mode |
| </title> |
| <para> |
| JPA 2.0 specification introduced the standard data cache configuration through the shared-cache-mode element or jakarta.persistence. |
| sharedCache.mode property. |
| </para> |
| <para> |
| When only the shared cache mode is configured to turn on the caching, the default data cache setting will be used. For example the |
| cache size will be set to default 1000. |
| </para> |
| <para> |
| When the shared cache mode and openjpa.DataCache are both configured, the JPA standard shared cache mode |
| configuration takes the precedence. |
| </para> |
| <para> |
| If the shared cache mode is to turn on the caching, the cache setting configured through openjpa.DataCache |
| , like cacheSize and SoftReferenceSize, will be used to initialize or manage the cache. The Types and ExcludeTypes |
| property in openjpa.DataCache will be ingnored since the shared cache mode in conjunction with the jakarta.persistence.Cacheable |
| annotation already defines what will be cached. |
| </para> |
| <example id="shared-cache-mode-none"> |
| <para> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true"/> |
| <property name="jakarta.persistence.sharedCache.mode" value="NONE"/> |
| </programlisting> |
| </para> |
| <para> |
| When the shared cache mode is set to NONE, the data cache will be disabled no matter how openjpa.DataCache is configured. |
| </para> |
| </example> |
| |
| <example id="shared-cache-mode-all"> |
| <para> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(ExcludedTypes=foo.bar.Person;foo.bar.Employee)"/> |
| <property name="jakarta.persistence.sharedCache.mode" value="ALL"/> |
| </programlisting> |
| </para> |
| <para> |
| When the shared cache mode is set to ALL, all entities will be cached no matter how openjpa.DataCache is configured. |
| </para> |
| </example> |
| |
| <example id="shared-cache-mode-enable-selective"> |
| <para> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(ExcludedTypes=foo.bar.Person;foo.bar.Employee)"/> |
| <property name="jakarta.persistence.sharedCache.mode" value="ENABLE_SELECTIVE"/> |
| </programlisting> |
| </para> |
| <para> |
| When the shared cache mode set to ENABLE_SELECTIVE, the entities with Cacheable(true) anotation will be cached. |
| ExcludedTypes will be ignored. |
| </para> |
| </example> |
| </section> |
| <section id="ref_guide_cache_distribution"> |
| <title>Distributing instances across cache partitions</title> |
| <para> |
| OpenJPA also supports a partitioned cache configuration where the cached |
| instances can be distributed across partitions by an application-defined |
| policy. Each partition behaves as a data cache by itself, identified by its name and can |
| be configured individually. The distribution policy |
| determines the specific partition that stores the state of a managed instance. |
| The default distribution policy distributes the instances by their type |
| as specified by the <literal>name</literal> attribute in <literal>@DataCache</literal> |
| annotation. Cache distribution policy is a simple interface that can be implemented |
| by an application to distribute among the partitions on a per instance basis. |
| To enable a partitioned cache set the <literal>openjpa.DataCache</literal> |
| property to <literal>partitioned</literal>, and configure individual partitions |
| as follows: |
| </para> |
| <example id="ref_guide_cache_conf_partition"> |
| <title> |
| Partitioned Data Cache |
| </title> |
| <programlisting> |
| <property name="openjpa.CacheDistributionPolicy" value="org.acme.foo.DistributionPolicy"/> |
| <property name="openjpa.DataCache" value="partitioned(PartitionType=concurrent,partitions= |
| '(name=a,cacheSize=100),(name=b,cacheSize=200)')"/> |
| </programlisting> |
| </example> |
| </section> |
| <para> |
| The distribution policy is configured by a full-qualified class name that implements |
| <literal>org.apache.openjpa.datacahe.CacheDistributionPolicy</literal>. The partitions |
| are specified as value of the <literal>partitions</literal> attribute as a series of |
| individually configurable plug-in strings. As the example shows, i) each partition plug-in configuration |
| must be enclosed in parentheses, ii) must be separated by comma and iii) the complete |
| set be enclosed in single quote. Each individual partition is a Data Cache by itself and |
| the class that implements the partition can be configured via <literal>PartitionType</literal> |
| attribute. The above example configuration will configure a partitioned cache with |
| two partitions named <literal>a</literal> and <literal>b</literal> of cache size 100 and 200, |
| respectively. The partitions are of <literal>concurrent</literal> type which is a mnemonic or alias |
| for <literal>org.apache.openjpa.datacache.ConcurrentDataCache</literal>. The <literal>PartitionType</literal> |
| is defaulted to <literal>concurrent</literal> though explicitly mentioned in this example. |
| </para> |
| </section> |
| <section id="ref_guide_cache_use"> |
| <title> |
| Data Cache Usage |
| </title> |
| <para> |
| The <literal>org.apache.openjpa.datacache</literal> package defines OpenJPA's |
| data caching framework. While you may use this framework directly (see its |
| <ulink url="../../apidocs/org/apache/openjpa/datacache/package-summary.html"> |
| Javadoc</ulink> for details), its APIs are meant primarily for service |
| providers. In fact, <xref linkend="ref_guide_cache_extension"/> below has |
| tips on how to use this package to extend OpenJPA's caching service yourself. |
| </para> |
| <para> |
| Rather than use the low-level <literal>org.apache.openjpa.datacache</literal> |
| package APIs, JPA users should typically access the data cache through the JPA |
| standard <classname>jakarta.persistence.Cache</classname> interface, or OpenJPA's |
| high-level |
| <ulink url="../../apidocs/org/apache/openjpa/persistence/StoreCache.html"> |
| <classname>org.apache.openjpa.persistence.StoreCache</classname></ulink> facade. |
| </para> |
| <para> |
| Both interfaces provide methods to evict data from the cache and detect whether |
| an entity is in the cache. The OpenJPA facade adds methods to pin and unpin |
| records, additional methods to evict data, and provides basic statistics of |
| number of read or write requests and hit ratio of the cache. |
| </para> |
| <section id="ref_guide_cache_use_JPA"> |
| <title>Using the JPA standard Cache interface</title> |
| You may obtain the <classname>jakarta.persistence.Cache</classname> through |
| the EntityManagerFactory.getCache() method. |
| <example id="ref_guide_cache_access_jpa_standard"> |
| <title> |
| Accessing the Cache |
| </title> |
| <programlisting> |
| import jakarta.persistence.Cache; |
| import jakarta.persistence.EntityManagerFactory; |
| import jakarta.persistence.Persistence; |
| . . . |
| EntityManagerFactory emf = |
| Persistence.createEntityManagerFactory("myPersistenceUnit"); |
| Cache cache = emf.getCache(); |
| . . . |
| </programlisting> |
| </example> |
| |
| <example id="ref_guide_cache_use_jpa_standard"> |
| <title>Using the jakarta.persistence.Cache interface</title> |
| <programlisting> |
| // Check whether the cache contains an entity with a provided ID |
| Cache cache = emf.getCache(); |
| boolean contains = cache.contains(MyEntity.class, entityID); |
| |
| // evict a specific entity from the cache |
| cache.evict(MyEntity.class, entityID); |
| |
| // evict all instances of an entity class from the cache |
| cache.evict(AnotherEntity.class); |
| |
| // evict everything from the cache |
| cache.evictAll(); |
| </programlisting> |
| </example> |
| </section> |
| <section id="ref_guide_cache_use_openJPA"> |
| <title>Using the OpenJPA StoreCache extensions</title> |
| <para> |
| You obtain the <classname>StoreCache</classname> through the <methodname> |
| OpenJPAEntityManagerFactory.getStoreCache</methodname> method. |
| </para> |
| <example id="ref_guide_cache_access_jpa"> |
| <title> |
| Accessing the StoreCache |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| ... |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| StoreCache cache = oemf.getStoreCache(); |
| ... |
| </programlisting> |
| Alternatively you can just cast the same object returned from |
| the EntityManager.getCache() method. |
| <programlisting> |
| import org.apache.openjpa.persistence.StoreCache; |
| ... |
| StoreCache cache = (StoreCache) emf.getCache(); |
| </programlisting> |
| </example> |
| <programlisting> |
| public void evict(Class cls, Object oid); |
| public void evictAll(); |
| public void evictAll(Class cls, Object... oids); |
| public void evictAll(Class cls, Collection oids); |
| </programlisting> |
| <para> |
| The <methodname>evict</methodname> methods tell the cache to release data. Each |
| method takes an entity class and one or more identity values, and releases the |
| cached data for the corresponding persistent instances. The <methodname> |
| evictAll</methodname> method with no arguments clears the cache. Eviction is |
| useful when the datastore is changed by a separate process outside OpenJPA's |
| control. In this scenario, you typically have to manually evict the data from |
| the datastore cache; otherwise the OpenJPA runtime, oblivious to the changes, |
| will maintain its stale copy. |
| </para> |
| <programlisting> |
| public void pin(Class cls, Object oid); |
| public void pinAll(Class cls, Object... oids); |
| public void pinAll(Class cls, Collection oids); |
| public void unpin(Class cls, Object oid); |
| public void unpinAll(Class cls, Object... oids); |
| public void unpinAll(Class cls, Collection oids); |
| </programlisting> |
| <para> |
| Most caches are of limited size. Pinning an identity to the cache ensures that |
| the cache will not kick the data for the corresponding instance out of the |
| cache, unless you manually evict it. Note that even after manual eviction, the |
| data will get pinned again the next time it is fetched from the store. You can |
| only remove a pin and make the data once again available for normal cache |
| overflow eviction through the <methodname>unpin</methodname> methods. Use |
| pinning when you want a guarantee that a certain object will always be available |
| from cache, rather than requiring a datastore trip. |
| </para> |
| |
| |
| <example id="ref_guide_cache_use_jpa"> |
| <title> |
| StoreCache Usage |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| ... |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| StoreCache cache = oemf.getStoreCache(); |
| cache.pin(Magazine.class, popularMag.getId()); |
| cache.evict(Magazine.class, changedMag.getId()); |
| </programlisting> |
| </example> |
| <para> |
| See the <classname>StoreCache</classname> |
| <ulink url="../../apidocs/org/apache/openjpa/persistence/StoreCache.html"> |
| Javadoc</ulink> for information on additional functionality it provides. Also, |
| <xref linkend="ref_guide_runtime"/> discusses OpenJPA's other extensions |
| to the standard set of JPA runtime interfaces. |
| </para> |
| </section> |
| <para> |
| The examples above include calls to <methodname>evict</methodname> to manually |
| remove data from the data cache. Rather than evicting objects from the data |
| cache directly, you can also configure OpenJPA to automatically evict objects |
| from the data cache when you use the <classname> |
| OpenJPAEntityManager</classname>'s eviction APIs. |
| </para> |
| <example id="ref_guide_cache_pmevict"> |
| <title> |
| Automatic Data Cache Eviction |
| </title> |
| <programlisting> |
| <property name="openjpa.BrokerImpl" value="EvictFromDataCache=true"/> |
| </programlisting> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| OpenJPAEntityManager oem = OpenJPAPersistence.cast(em); |
| oem.evict(changedMag); // will evict from data cache also |
| </programlisting> |
| </example> |
| </section> |
| |
| <section id="ref_guide_cache_statistics"> |
| <title> |
| Cache Statistics |
| </title> |
| <indexterm> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| statistics |
| </secondary> |
| </indexterm> |
| |
| <para> |
| Number of requests to read and write requests and hit ratio of the |
| data cache is available via |
| <ulink url="../../apidocs/org/apache/openjpa/datacache/CacheStatistics.html"> |
| <classname>org.apache.openjpa.datacache.CacheStatistics</classname></ulink> |
| interface. The collection of cache statistics is disabled by default and needs to be enabled on a per cache basis. By default |
| all counts returned from the CacheStatistics interface will return 0. |
| <example id="ref_guide_cache_enablestats"> |
| <title> |
| Configuring CacheStatistics |
| </title> |
| <programlisting> |
| <property name="openjpa.DataCache" value="true(EnableStatistics=true)"/> |
| </programlisting> |
| </example> |
| Once cache statistics are enabled you can access them via StoreCache |
| <programlisting> |
| import org.apache.openjpa.datacache.CacheStatistics; |
| ... |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| CacheStatistics statistics = oemf.getStoreCache().getCacheStatistics(); |
| </programlisting> |
| The statistics includes number of read and write requests made to the cache |
| since start and last reset. The statistics can be obtained also per class basis. |
| <programlisting> |
| public interface org.apache.openjpa.datacache.CacheStatistics extends java.io.Serializable{ |
| // Statistics since last reset |
| public long getReadCount(); |
| public long getHitCount(); |
| public long getWriteCount(); |
| |
| // Statistics since start |
| public long getTotalReadCount(); |
| public long getTotalHitCount(); |
| public long getTotalWriteCount(); |
| |
| // Per-Class statistics since last reset |
| public long getReadCount(java.lang.Class); |
| public long getHitCount(java.lang.Class); |
| public long getWriteCount(java.lang.Class); |
| |
| // Per-Class statistics since start |
| public long getTotalReadCount(java.lang.Class); |
| public long getTotalHitCount(java.lang.Class); |
| public long getTotalWriteCount(java.lang.Class); |
| |
| // Starting and last reset time |
| public java.util.Date since(); |
| public java.util.Date start(); |
| |
| // Resets the statistics. |
| public void reset(); |
| |
| // Returns whether or not statistics will be collected. |
| public boolean isEnabled(); |
| } |
| </programlisting> |
| Collecting per-class statistics depends on determining the runtime type of a |
| cached data element, when the given context does not permit determination of |
| exact runtime type, the statistics is registered against generic |
| <classname>java.lang.Object</classname>. Also each method that accepts Class |
| argument, treats null argument as <classname>java.lang.Object</classname> |
| </para> |
| |
| </section> |
| |
| <section id="ref_guide_cache_query"> |
| <title> |
| Query Cache |
| </title> |
| <indexterm zone="ref_guide_cache_query"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| query cache |
| </secondary> |
| </indexterm> |
| <indexterm zone="ref_guide_cache_query"> |
| <primary> |
| Query |
| </primary> |
| <secondary> |
| result caching |
| </secondary> |
| </indexterm> |
| <para> |
| In addition to the data cache, the <literal>org.apache.openjpa.datacache |
| </literal> package defines service provider interfaces for a query cache. The |
| query cache is disabled by default and needs to be enabled separately from the data cache. |
| The query cache stores the object ids returned by query executions. When you run a query, |
| OpenJPA assembles a key based on the query properties and the parameters used at |
| execution time, and checks for a cached query result. If one is found, the |
| object ids in the cached result are looked up, and the resultant |
| persistence-capable objects are returned. Otherwise, the query is executed |
| against the database, and the object ids loaded by the query are put into the |
| cache. The object id list is not cached until the list returned at query |
| execution time is fully traversed. |
| </para> |
| <para> |
| OpenJPA exposes a high-level interface to the query cache through the |
| <ulink url="../../apidocs/org/apache/openjpa/persistence/QueryResultCache.html"> |
| <classname>org.apache.openjpa.persistence.QueryResultCache</classname></ulink> |
| class. You can access this class through the <classname> |
| OpenJPAEntityManagerFactory</classname>. |
| </para> |
| <example id="ref_guide_cache_queryaccess"> |
| <title> |
| Accessing the QueryResultCache |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| QueryResultCache qcache = oemf.getQueryResultCache(); |
| </programlisting> |
| </example> |
| <para> |
| The default query cache implementation caches 100 query executions in a |
| least-recently-used cache. This can be changed by setting the cache size in the |
| <literal>CacheSize</literal> plugin property. Like the data cache, the query |
| cache also has a backing soft reference map. The <literal>SoftReferenceSize |
| </literal> property controls the size of this map. It is disabled by default. |
| </para> |
| <example id="ref_guide_cache_cachesize"> |
| <title> |
| Query Cache Size |
| </title> |
| <programlisting> |
| <property name="openjpa.QueryCache" value="true(CacheSize=1000, SoftReferenceSize=100)"/> |
| </programlisting> |
| </example> |
| <para> |
| To disable the query cache (default), set the <literal>openjpa.QueryCache |
| </literal> property to <literal>false</literal>: |
| </para> |
| <example id="ref_guide_cache_disablequery"> |
| <title> |
| Disabling the Query Cache |
| </title> |
| <programlisting> |
| <property name="openjpa.QueryCache" value="false"/> |
| </programlisting> |
| </example> |
| <para> |
| Query Cache's default behaviour on eviction is to evict all the queries from |
| the cache if any of the entities that are in the access path of the query are |
| modified. Scanning through the whole query cache to evict the queries upon an |
| entity update slows down the entity update action. |
| |
| The configurable eviction policy "timestamp" is to track the timestamp of the |
| query and the timestamp of last update for each entity class and compare the |
| timestamps when retrieving the query for reuse. If the timestamp of the query |
| result is older than the last update time of any entity in the access path of |
| the query, the query result would not be reused and the query result would be |
| evicted from the query cache. |
| To configure the <literal>EvictPolicy</literal> to timestamp, |
| here is an example: |
| </para> |
| <example id="ref_guide_cache_evictionPolicy"> |
| <title> |
| Query Cache Eviction Policy |
| </title> |
| <programlisting> |
| <property name="openjpa.QueryCache" value="true(EvictPolicy='timestamp')"/> |
| </programlisting> |
| </example> |
| <para> |
| There are certain situations in which the query cache is bypassed: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Caching is not used for in-memory queries (queries in which the candidates are a |
| collection instead of a class or <classname>Extent</classname>). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Caching is not used in transactions that have <literal>IgnoreChanges</literal> |
| set to <literal>false</literal> and in which modifications to classes in the |
| query's access path have occurred. If none of the classes in the access path |
| have been touched, then cached results are still valid and are used. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Caching is not used in pessimistic transactions, since OpenJPA must go to the |
| database to lock the appropriate rows. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Caching is not used when the data cache does not have any cached data for an |
| id in a query result. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Queries that use persistence-capable objects as parameters are only cached if |
| the parameter is directly compared to field, as in: |
| </para> |
| <programlisting> |
| select e from Employee e where e.company.address = :addr |
| </programlisting> |
| <para> |
| If you extract field values from the parameter in your query string, or if the |
| parameter is used in collection element comparisons, the query is not cached. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Queries that result in projections of custom field types or <classname> |
| BigDecimal</classname> or <classname>BigInteger</classname> fields are not |
| cached. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| Cache results are removed from the cache when instances of classes in a cached |
| query's access path are touched. That is, if a query accesses data in class |
| <classname>A</classname>, and instances of class <classname>A</classname> are |
| modified, deleted, or inserted, then the cached query result is dropped from the |
| cache. |
| </para> |
| <para> |
| It is possible to tell the query cache that a class has been altered. This is |
| only necessary when the changes occur via direct modification of the database |
| outside of OpenJPA's control. You can also evict individual queries, or clear |
| the entire cache. |
| </para> |
| <programlisting> |
| public void evict(Query q); |
| public void evictAll(Class cls); |
| public void evictAll(); |
| </programlisting> |
| <para> |
| For JPA queries with parameters, set the desired parameter values into the |
| <ulink url="http://download.oracle.com/javaee/6/api/javax/persistence/Query.html"> |
| <classname>Query</classname></ulink> instance before calling the above methods. |
| </para> |
| <example id="ref_guide_cache_query_classchange"> |
| <title> |
| Evicting Queries |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| QueryResultCache qcache = oemf.getQueryResultCache(); |
| |
| // evict all queries that can be affected by changes to Magazines |
| qcache.evictAll(Magazine.class); |
| |
| // evict an individual query with parameters |
| EntityManager em = emf.createEntityManager(); |
| Query q = em.createQuery(...). |
| setParameter(0, paramVal0). |
| setParameter(1, paramVal1); |
| qcache.evict(q); |
| </programlisting> |
| </example> |
| <para> |
| When using one of OpenJPA's distributed cache implementations, it is necessary |
| to perform this in every JVM - the change notification is not propagated |
| automatically. When using a third-party coherent caching solution, |
| it is not necessary to do this in every JVM (although it won't hurt to do so), |
| as the cache results are stored directly in the coherent cache. |
| </para> |
| <para> |
| Queries can also be pinned and unpinned through the <classname> |
| QueryResultCache</classname>. The semantics of these operations are the same |
| as pinning and unpinning data from the data cache. |
| </para> |
| <programlisting> |
| public void pin(Query q); |
| public void unpin(Query q); |
| </programlisting> |
| <para> |
| For JPA queries with parameters, set the desired parameter values into the |
| <ulink url="http://download.oracle.com/javaee/6/api/javax/persistence/Query.html"> |
| <classname>Query</classname></ulink> instance before calling the above methods. |
| </para> |
| <para> |
| The following example shows these APIs in action. |
| </para> |
| <example id="ref_guide_cache_query_pin"> |
| <title> |
| Pinning, and Unpinning Query Results |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf); |
| QueryResultCache qcache = oemf.getQueryResultCache(); |
| EntityManager em = emf.createEntityManager(); |
| |
| Query pinQuery = em.createQuery(...). |
| setParameter(0, paramVal0). |
| setParameter(1, paramVal1); |
| qcache.pin(pinQuery); |
| Query unpinQuery = em.createQuery(...). |
| setParameter(0, paramVal0). |
| setParameter(1, paramVal1); |
| qcache.unpin(unpinQuery); |
| </programlisting> |
| </example> |
| <para> |
| Pinning data into the cache instructs the cache to not expire the pinned results |
| when cache flushing occurs. However, pinned results will be removed from the |
| cache if an event occurs that invalidates the results. |
| </para> |
| <para> |
| You can disable caching on a per-<classname>EntityManager</classname> or |
| per-<classname>Query</classname> basis: |
| </para> |
| <example id="ref_guide_cache_query_disable"> |
| <title> |
| Disabling and Enabling Query Caching |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| // temporarily disable query caching for all queries created from em |
| OpenJPAEntityManager oem = OpenJPAPersistence.cast(em); |
| oem.getFetchPlan().setQueryResultCacheEnabled(false); |
| |
| // re-enable caching for a particular query |
| OpenJPAQuery oq = oem.createQuery(...); |
| oq.getFetchPlan().setQueryResultCacheEnabled(true); |
| </programlisting> |
| </example> |
| </section> |
| <section id="ref_guide_cache_extension"> |
| <title> |
| Cache Extension |
| </title> |
| <indexterm zone="ref_guide_cache_extension"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| data cache |
| </secondary> |
| <tertiary> |
| extension |
| </tertiary> |
| </indexterm> |
| <indexterm zone="ref_guide_cache_extension"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| query cache |
| </secondary> |
| <tertiary> |
| extension |
| </tertiary> |
| </indexterm> |
| <para> |
| The provided data cache classes can be easily extended to add additional |
| functionality. If you are adding new behavior, you should extend <classname> |
| org.apache.openjpa.datacache.ConcurrentDataCache</classname>. To use your own storage |
| mechanism, extend <classname>org.apache.openjpa.datacache.AbstractDataCache |
| </classname> (preferred), or implement <classname>org.apache.openjpa.datacache.DataCache |
| </classname> directly. If you want to implement a distributed cache that uses an |
| unsupported method for communications, create an implementation of <classname> |
| org.apache.openjpa.event.RemoteCommitProvider</classname>. This process is |
| described in greater detail in |
| <xref linkend="ref_guide_event_customization"/>. |
| </para> |
| <para> |
| The query cache is just as easy to extend. Add functionality by extending the |
| default <classname>org.apache.openjpa.datacache.ConcurrentQueryCache</classname>. |
| Implement your own storage mechanism for query results by extending <classname> |
| org.apache.openjpa.datacache.AbstractQueryCache</classname> (preferred) or implementing the |
| <classname>org.apache.openjpa.datacache.QueryCache</classname> interface |
| directly. |
| </para> |
| </section> |
| <section id="ref_guide_cache_notes"> |
| <title> |
| Important Notes |
| </title> |
| <itemizedlist> |
| <listitem> |
| <para> |
| The default cache implementations <emphasis>do not</emphasis> automatically |
| refresh objects in other <classname>EntityManager</classname>s when the cache |
| is updated or invalidated. This behavior would not be compliant with the JPA |
| specification. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Invoking <methodname>OpenJPAEntityManager.evict</methodname><emphasis> does not |
| </emphasis> result in the corresponding data being dropped from the data cache, |
| unless you have set the proper configuration options as explained above (see |
| <xref linkend="ref_guide_cache_pmevict"/>). Other methods related to the |
| <classname>EntityManager</classname> cache also do not affect the data cache. |
| </para> |
| <para> |
| The data cache assumes that it is up-to-date with respect to the datastore, so |
| it is effectively an in-memory extension of the database. To manipulate the data |
| cache, you should generally use the data cache facades presented in this |
| chapter. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| <section id="datastore_cache_issues"> |
| <title> |
| Known Issues and Limitations |
| </title> |
| <indexterm zone="datastore_cache_issues"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| issues and limitations |
| </secondary> |
| </indexterm> |
| <itemizedlist> |
| <listitem> |
| <para> |
| When using datastore (pessimistic) transactions in concert with the distributed |
| caching implementations, it is possible to read stale data when reading data |
| outside a transaction. |
| </para> |
| <para> |
| For example, if you have two JVMs (JVM A and JVM B) both communicating with each |
| other, and JVM A obtains a data store lock on a particular object's underlying |
| data, it is possible for JVM B to load the data from the cache without going to |
| the datastore, and therefore load data that should be locked. This will only |
| happen if JVM B attempts to read data that is already in its cache during the |
| period between when JVM A locked the data and JVM B received and processed the |
| invalidation notification. |
| </para> |
| <para> |
| This problem is impossible to solve without putting together a two-phase commit |
| system for cache notifications, which would add significant overhead to the |
| caching implementation. As a result, we recommend that people use optimistic |
| locking when using data caching. If you do not, then understand that some of |
| your non-transactional data may not be consistent with the datastore. |
| </para> |
| <para> |
| Note that when loading objects in a transaction, the appropriate datastore |
| transactions will be obtained. So, transactional code will maintain its |
| integrity. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <classname>Extent</classname>s are not cached. So, if you plan on iterating |
| over a list of all the objects in an <classname>Extent</classname> on a regular |
| basis, you will only benefit from caching if you do so with a <classname>Query |
| </classname> instead: |
| </para> |
| <example id="ref_guide_cache_limits_extent"> |
| <title> |
| Query Replaces Extent |
| </title> |
| <programlisting> |
| import org.apache.openjpa.persistence.*; |
| |
| ... |
| |
| OpenJPAEntityManager oem = OpenJPAPersistence.cast(em); |
| Extent extent = oem.createExtent(Magazine.class, false); |
| |
| // This iterator does not benefit from caching... |
| Iterator uncachedIterator = extent.iterator(); |
| |
| // ... but this one does. |
| OpenJPAQuery extentQuery = oem.createQuery(...); |
| extentQuery.setSubclasses(false); |
| Iterator cachedIterator = extentQuery.getResultList().iterator(); |
| </programlisting> |
| </example> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| <section id="ref_guide_cache_querycomp"> |
| <title> |
| Query Compilation Cache |
| </title> |
| <indexterm zone="ref_guide_cache_querycomp"> |
| <primary> |
| caching |
| </primary> |
| <secondary> |
| query compilation cache |
| </secondary> |
| </indexterm> |
| <para> |
| The query compilation cache is a <classname>Map</classname> used to cache |
| parsed query strings. As a result, most queries are only parsed once in |
| OpenJPA, and cached thereafter. You can control the compilation cache through |
| the <link linkend="openjpa.QueryCompilationCache"><literal> |
| openjpa.QueryCompilationCache</literal></link> configuration property. This |
| property accepts a plugin string (see <xref linkend="ref_guide_conf_plugins"/>) |
| describing the <classname>Map</classname> used to associate query strings and |
| their parsed form. This property accepts the following aliases: |
| </para> |
| <table> |
| <title> |
| Pre-defined aliases |
| </title> |
| <tgroup cols="3" align="left" colsep="1" rowsep="1"> |
| <colspec colname="alias"/> |
| <colspec colname="value"/> |
| <colspec colname="notes"/> |
| <thead> |
| <row> |
| <entry colname="alias">Alias</entry> |
| <entry colname="value">Value</entry> |
| <entry colname="notes">Notes</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry colname="alias"> |
| <literal>true</literal> |
| </entry> |
| <entry colname="value"> |
| <literal>org.apache.openjpa.util.CacheMap</literal> |
| </entry> |
| <entry colname="notes"> |
| The default option. Uses a |
| <ulink url="../../apidocs/org/apache/openjpa/util/CacheMap.html"> |
| <literal>CacheMap</literal></ulink> to store compilation data. |
| <literal>CacheMap</literal> maintains a fixed number of cache entries, and an |
| optional soft reference map for entries that are moved out of the LRU space. |
| So, for applications that have a monotonically increasing number of distinct |
| queries, this option can be used to ensure that a fixed amount of memory is |
| used by the cache. |
| </entry> |
| </row> |
| <row> |
| <entry colname="alias"><literal>all</literal></entry> |
| <entry colname="value"> |
| <literal>org.apache.openjpa.lib.util.ConcurrentHashMap</literal> |
| </entry> |
| <entry colname="notes"> |
| This is the fastest option, but compilation data is never dropped from the |
| cache, so if you use a large number of dynamic queries, this option may result |
| in ever-increasing memory usage. Note that if your queries only differ in the |
| values of the parameters, this should not be an issue. |
| </entry> |
| </row> |
| <row> |
| <entry colname="alias"><literal>false</literal></entry> |
| <entry colname="value"><emphasis>none</emphasis></entry> |
| <entry colname="notes"> |
| Disables the compilation cache. |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section id="ref_guide_cache_querysql"> |
| <title>Prepared SQL Cache</title> |
| <indexterm zone="ref_guide_cache_querysql"> |
| <primary>caching</primary> |
| <secondary>query sql cache</secondary> |
| </indexterm> |
| <para> |
| Prepared SQL Cache caches SQL statements corresponding to JPQL queries. |
| If a query is executed more than once in the same or different persistence |
| contexts, the SQL statement generated during the first execution is cached and |
| executed directly for subsequent execution. Direct execution of SQL offers |
| significant performance gain as it saves the cost of parsing query string and, |
| more importantly, populating the query expression tree during every execution. |
| Relative performance gain becomes higher as the complexity of forming a SQL |
| query from a JPQL string increases. For example, a JPQL query <code>Q1</code> |
| that involves multiple joins across tables takes more computation to translate |
| into a SQL statement than a JPQL query <code>Q2</code> to select by simple |
| primary key identifier. Correspondingly, repeated execution of <code>Q1</code> |
| will gain more performance advantage than <code>Q2</code> with Prepared SQL |
| Cache. |
| </para> |
| <para> |
| Prepared SQL Cache is configured by the <link linkend="openjpa.jdbc.QuerySQLCache"> |
| <literal>openjpa.jdbc.QuerySQLCache</literal></link> configuration property. This |
| property accepts a plugin string (see <xref linkend="ref_guide_conf_plugins"/>) |
| with value of <literal>true</literal> or <literal>false</literal>. The default |
| is <literal>true</literal>. The execution statistics of the cached queries can be |
| optionally collected as |
| <programlisting> |
| <property name="openjpa.jdbc.QuerySQLCache" value="true(EnableStatistics=true)"> |
| </programlisting> |
| The <ulink url="../../apidocs/org/apache/openjpa/kernel/QueryStatistics.html"> |
| <code>QueryStatistics</code></ulink> can be accessed via <code>PreparedQueryCache.getStatistics()</code>. |
| |
| </para> |
| <table> |
| <title> |
| Pre-defined aliases |
| </title> |
| <tgroup cols="3" align="left" colsep="1" rowsep="1"> |
| <colspec colname="alias"/> |
| <colspec colname="value"/> |
| <colspec colname="notes"/> |
| <thead> |
| <row> |
| <entry colname="alias">Alias</entry> |
| <entry colname="value">Value</entry> |
| <entry colname="notes">Notes</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry colname="alias"> |
| <literal>true</literal> |
| </entry> |
| <entry colname="value"> |
| <literal>org.apache.openjpa.util.CacheMap</literal> |
| </entry> |
| <entry colname="notes"> |
| The default option. Uses a |
| <ulink url="../../apidocs/org/apache/openjpa/util/CacheMap.html"> |
| <literal>CacheMap</literal></ulink> to store SQL string. |
| <literal>CacheMap</literal> maintains a fixed number of cache entries, and an |
| optional soft reference map for entries that are moved out of the LRU space. |
| So, for applications that have a monotonically increasing number of distinct |
| queries, this option can be used to ensure that a fixed amount of memory is |
| used by the cache. |
| </entry> |
| </row> |
| <row> |
| <entry colname="alias"><literal>false</literal></entry> |
| <entry colname="value"><emphasis>none</emphasis></entry> |
| <entry colname="notes"> |
| Disables the SQL cache. |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| <para> |
| Following salient points to be noted regarding usage of Prepared Query Cache. |
| <itemizedlist> |
| <listitem> |
| <para> |
| Prepared Query Cache uses the original JPQL string as the key to index the |
| corresponding SQL statement. Hence the JPQL strings that are semantically |
| identical but differ by character case or identification variables are |
| considered as different by this cache. One of the implications is that the |
| applications can gain better advantage from the Prepared Query Cache by |
| using parameters in their JPQL query rather than concatenating the parameter |
| values in the query string itself . |
| </para> |
| <para> |
| For example, contrast the following two examples of executing JPQL queries. |
| <example id="jpa_caching_hardcode_jpql"> |
| <title>Hardcoded Selection Value in JPQL Query</title> |
| <programlisting> |
| String jpql = "SELECT p FROM Person p WHERE p.name='John'"; |
| List johns = em.createQuery(jpql).getResultList(); |
| jpql = "SELECT p FROM Person p WHERE p.name='Tom'"; |
| List toms = em.createQuery(jpql).getResultList(); |
| </programlisting> |
| </example> |
| In <xref linkend="jpa_caching_hardcode_jpql"></xref>, the queries have |
| <emphasis>hardcoded</emphasis> the selection value for the <code>p.name</code> |
| field. Prepared Query Cache will not recognize the second execution as |
| same as the first, though both will result in same SQL statement. |
| </para> |
| <para> |
| While in <xref linkend="jpa_caching_parametrize_jpql"></xref>, the |
| selection value for the <code>p.name</code> field is parameterized. |
| Prepared Query Cache will recognize the second execution as |
| same as the first, and will execute the cached SQL statement directly. |
| |
| <example id="jpa_caching_parametrize_jpql"> |
| <title>Parameterized Selection Value in JPQL Query</title> |
| <programlisting> |
| String jpql = "SELECT p FROM Person p WHERE p.name=:name"; |
| List johns = em.createQuery(jpql).setParameter("name","John").getResultList(); |
| List toms = em.createQuery(jpql).setParameter("name","Tom").getResultList(); |
| </programlisting> |
| </example> |
| </para> |
| </listitem> |
| |
| <listitem> |
| A JPQL query may not always translate into a <emphasis>single</emphasis> |
| SQL query. The JPQL queries that require multiple select statements are |
| never cached. |
| </listitem> |
| <listitem> |
| Same JPQL query may result into different SQL statements under different |
| execution context. Execution context parameters such as fetch configuration |
| or locking mode determine the resultant SQL. However, Prepared SQL Cache |
| <emphasis>does not</emphasis> capture the execution context parameters |
| while caching a generated SQL. |
| </listitem> |
| <listitem> |
| The named or positional parameters of a JPQL query can be set to different |
| values across executions. In general, the corresponding cached SQL statement |
| will be re-parameterized accordingly. However, the parameter value itself can |
| determine the SQL query. For example, when a JPQL query compares a relation |
| field for equality against a parameter <code>p</code>, whether the actual |
| value of <code>p</code> is <code>null</code> or not will determine the |
| generated SQL statement. Another example is collection valued parameter for |
| <code>IN</code> expression. Each element of a collection valued parameter |
| results into a SQL parameter. If a collection valued parameter across |
| executions are set to different number of elements, then the parameters of |
| the cached SQL do not correspond. If such situations are encountered while |
| re-parameterizing the cached SQL, the cached version is not reused and the |
| original JPQL query is used to generate a new SQL statement for execution. |
| </listitem> |
| <listitem> |
| JPQL query that returns a <emphasis>numeric</emphasis> value such as |
| <code>SELECT count(p) FROM PObject p</code> is never cached. |
| </listitem> |
| </itemizedlist> |
| </para> |
| <para> |
| Several mechanisms are available to the application to bypass SQL caching |
| for a JPQL query. |
| <itemizedlist> |
| <listitem>A user application can disable Prepared SQL Cache |
| for entire lifetime of a persistence context by invoking the following |
| method on OpenJPA's EntityManager SPI interface: |
| <programlisting> |
| <methodname>OpenJPAEntityManagerSPI.setQuerySQLCache(boolean)</methodname> |
| </programlisting> |
| </listitem> |
| <listitem> |
| A user application can instruct particular execution of a JPQL query to |
| ignore any cached SQL query, by setting |
| <literal>QueryHints.HINT_IGNORE_PREPARED_QUERY</literal> or |
| <literal>"openjpa.hint.IgnorePreparedQuery"</literal> to <literal>true</literal> |
| via standard <literal>jakarta.persistence.Query.setHint(String, Object)</literal> method. If a |
| SQL query has been cached corresponding to the JPQL query prior to this |
| execution, then the cached SQL remains in the cache and will be reused |
| for any subsequent execution of the same JPQL query. |
| </listitem> |
| <listitem> |
| A user application can instruct all subsequent execution of a JPQL query to |
| ignore any cached SQL query, by setting |
| <literal>QueryHints.HINT_INVALIDATE_PREPARED_QUERY</literal> or |
| <literal>"openjpa.hint.InvalidatePreparedQuery"</literal> to <literal>true</literal> |
| The SQL query is removed from the cache. Also the JPQL query will never be |
| cached again during the lifetime of the entire persistence unit. |
| </listitem> |
| <listitem> |
| Plug-in property <literal>openjpa.jdbc.QuerySQLCache</literal> can be |
| configured to exclude certain JPQL queries as shown below. |
| <programlisting> |
| <property name="openjpa.jdbc.QuerySQLCache" value="true(excludes='select c from Company c;select d from Department d')"/> |
| </programlisting> |
| will never cache JPQL queries <code>select c from Company c</code> and |
| <code>select d from Department d</code>. |
| </listitem> |
| </itemizedlist> |
| </para> |
| |
| </section> |
| </chapter> |