Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/JPA/Caching"

m (xref to/from doc)
(Using the @Cache Annotation)
 
(3 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
[[Category:EclipseLink/Example/JPA|Caching]]
 
[[Category:EclipseLink/Example/JPA|Caching]]
  
==How to use EclispeLink Caching==
+
==How to use EclipseLink Caching==
  
 
By default EclipseLink uses a shared object cache, that caches a subset of all objects read and persisted for the persistence unit.
 
By default EclipseLink uses a shared object cache, that caches a subset of all objects read and persisted for the persistence unit.
Line 90: Line 90:
 
   type=CacheType.SOFT, // Cache everything until the JVM decides memory is low.
 
   type=CacheType.SOFT, // Cache everything until the JVM decides memory is low.
 
   size=64000  // Use 64,000 as the initial cache size.
 
   size=64000  // Use 64,000 as the initial cache size.
   expiry=36000000,  // 10 minutes
+
   expiry=360000,  // 6 minutes
 
   coordinationType=CacheCoordinationType.INVALIDATE_CHANGED_OBJECTS  // if cache coordination is used, only send invalidation messages.
 
   coordinationType=CacheCoordinationType.INVALIDATE_CHANGED_OBJECTS  // if cache coordination is used, only send invalidation messages.
 
)
 
)
Line 98: Line 98:
 
</source>
 
</source>
  
''''' Attributes of the @Cache Annotation'''''
+
For more information on <code>@Cache</code> options and configuring caching, see [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Configuring|Configuring Caching]].
 
+
{| class="RuleFormalWideMax" dir="ltr" title="Attributes of the @Cache Annotation" summary="This table lists the attributes of EclipseLink JPA Cache annotation" width="100%" border="1" frame="border" rules="all" cellpadding="3" frame="border" rules="all"
+
|- align="left" valign="top"
+
! id="r1c1-t19" align="left" valign="bottom" | '''Attribute'''
+
! id="r1c2-t19" align="left" valign="bottom" | '''Description'''
+
! id="r1c3-t19" align="left" valign="bottom" | '''Default'''
+
! id="r1c4-t19" align="left" valign="bottom" | '''Required or Optional'''
+
! id="r1c5-t19" align="left" valign="bottom" | '''Override with Persistence Unit Property'''
+
|- align="left" valign="top"
+
| id="r2c1-t19" headers="r1c1-t19" align="left" |
+
<tt>type</tt>
+
| headers="r2c1-t19 r1c2-t19" align="left" |
+
Set this attribute to the type (<tt>org.eclipse.persistence.annotations.CacheType</tt> enumerated type) of the cache that you will be using:
+
*FULL
+
*WEAK
+
*SOFT
+
*SOFT_WEAK
+
*HARD_WEAK
+
*CACHE (not recommended)
+
*NONE (not recommended, use shared=false instead)
+
| headers="r2c1-t19 r1c3-t19" align="left" |
+
<tt>CacheType.SOFT_WEAK</tt>
+
| headers="r2c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r2c1-t19 r1c5-t19" align="left" |
+
* <tt>eclipselink.cache.type.<ENTITY></tt>
+
* <tt>eclipselink.cache.type.default</tt>
+
|- align="left" valign="top"
+
| id="r3c1-t19" headers="r1c1-t19" align="left" |
+
<tt>size</tt>
+
| headers="r3c1-t19 r1c2-t19" align="left" |
+
Set this attribute to an <tt>int</tt> value to define the size of cache to use (number of objects).
+
| headers="r3c1-t19 r1c3-t19" align="left" |
+
100
+
| headers="r3c1-t19 r1c4-t19" align="left" | <br>
+
| headers="r3c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r4c1-t19" headers="r1c1-t19" align="left" |
+
<tt>shared</tt>
+
| headers="r4c1-t19 r1c2-t19" align="left" |
+
Indicate whether cached instances should be in the shared cache or in a client isolated cache (see [[Using%20Advanced%20Unit%20of%20Work%20API%20(ELUG)#Isolated Client Session Cache|Isolated Client Session Cache]]).
+
This allows the shared cache (L2 cache) to be disabled.
+
* <tt>true</tt> - use shared cache for cached instances;
+
* <tt>false</tt> - use client isolated cache for cached instances (no L2 cache).
+
| headers="r4c1-t19 r1c3-t19" align="left" |
+
<tt>true</tt>
+
| headers="r4c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r4c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r5c1-t19" headers="r1c1-t19" align="left" |
+
<tt>expiry</tt>
+
| headers="r5c1-t19 r1c2-t19" align="left" |
+
The <tt>int</tt> value to enable the expiration of the cached instance after a fixed period of time (milliseconds). Queries executed against the cache after this will be forced back to the database for a refreshed copy.
+
| headers="r5c1-t19 r1c3-t19" align="left" |
+
-1 (no expiry)
+
| headers="r5c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r5c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r6c1-t19" headers="r1c1-t19" align="left" |
+
<tt>expiryTimeOfDay</tt>
+
| headers="r6c1-t19 r1c2-t19" align="left" |
+
Specific time of day (<tt>org.eclipse.persistence.annotations.TimeOfDay</tt>) when the cached instance will expire. Queries executed against the cache after this will be forced back to the database for a refreshed copy.
+
| headers="r6c1-t19 r1c3-t19" align="left" |
+
<tt>@TimeOfDay(specified=false)</tt>
+
| headers="r6c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r6c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r7c1-t19" headers="r1c1-t19" align="left" |
+
<tt>alwaysRefresh</tt>
+
| headers="r7c1-t19 r1c2-t19" align="left" |
+
Set to a <tt>boolean</tt> value of <tt>true</tt> to force all queries that go to the database to always refresh the cache.
+
| headers="r7c1-t19 r1c3-t19" align="left" |
+
<tt>false</tt>
+
| headers="r7c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r7c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r8c1-t19" headers="r1c1-t19" align="left" |
+
<tt>refreshOnlyIfNewer</tt>
+
| headers="r8c1-t19 r1c2-t19" align="left" |
+
Set to a <tt>boolean</tt> value of <tt>true</tt> to force all queries that go to the database to refresh the cache only if the data received from the database by a query is newer than the data in the cache (as determined by the optimistic locking field).
+
 
+
Note: This option only applies if one of the other refreshing options, such as <tt>alwaysRefresh</tt>, is already enabled.
+
 
+
Note: A version field is necessary to apply this feature.
+
| headers="r8c1-t19 r1c3-t19" align="left" |
+
<tt>false</tt>
+
| headers="r8c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r8c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r9c1-t19" headers="r1c1-t19" align="left" |
+
<tt>disableHits</tt>
+
| headers="r9c1-t19 r1c2-t19" align="left" |
+
Set to a <tt>boolean</tt> value of <tt>true</tt> to force all queries to bypass the cache for hits, but still resolve against the cache for identity. This forces all queries to hit the database.
+
| headers="r9c1-t19 r1c3-t19" align="left" |
+
<tt>false</tt>
+
| headers="r9c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r9c1-t19 r1c5-t19" align="left" | <br>
+
|- align="left" valign="top"
+
| id="r10c1-t19" headers="r1c1-t19" align="left" |
+
<tt>coordinationType</tt>
+
| headers="r10c1-t19 r1c2-t19" align="left" |
+
Set this attribute to the cache coordination mode (<tt>org.eclipse.persistence.annotations.CacheCoordinationType</tt> enumerated type).
+
| headers="r10c1-t19 r1c3-t19" align="left" |
+
<tt>CacheCoordinationType.SEND_OBJECT_CHANGES</tt>
+
| headers="r10c1-t19 r1c4-t19" align="left" |
+
optional
+
| headers="r10c1-t19 r1c5-t19" align="left" | <br>
+
|}
+
  
 
== Caching in Clustered Environments ==
 
== Caching in Clustered Environments ==
Line 223: Line 109:
 
* Cache invalidation based on time-to-live or time-of-day.
 
* Cache invalidation based on time-to-live or time-of-day.
 
* Optimistic locking will prevent updates to stale objects, and trigger the objects to be invalidated in the cache.
 
* Optimistic locking will prevent updates to stale objects, and trigger the objects to be invalidated in the cache.
 +
 +
See, [[EclipseLink/Examples/JPA/CacheCoordination| How to enable cache coordination]]

Latest revision as of 09:54, 13 May 2013

How to use EclipseLink Caching

By default EclipseLink uses a shared object cache, that caches a subset of all objects read and persisted for the persistence unit. The EclipseLink shared cache differs from the local EntityManager cache. The shared cache exists for the duration of the persistence unit (EntityManagerFactory, or server) and is shared by all EntityManagers and users of the persistence unit. The local EntityManager cache is not shared, and only exists for the duration of the EntityManager or transaction.

The benefit of the shared cache, is that once an object has been read, if it is read again using the find operation, the database does not need to be accessed. Also if the object is read through any Query, it will not need to be rebuilt, and its relationships will not need to be re-fetched.

The limitation of the shared cache, is that if the database is changed directly through JDBC, or by another application or server, the objects in the shared cache will be stale.

EclipseLink offers several mechanism to deal with stale data including:

  • Refreshing
  • Invalidation
  • Optimistic locking
  • Cache coordination

The shared cache can also be disabled. This can be done using the persistence unit property:

<property name="eclipselink.cache.shared.default" value="false"/>

Or, in JPA 2.0 the shared-cache-mode element in the persistence.xml can be used,

<shared-cache-mode>NONE</shared-cache-mode>

Or can be selectively enabled/disabled using the @Cache annotation. Or in JPA 2.0 using the @Cacheable annotation.

EclipseLink also offers several different caching strategies, the configure how many objects are cached, and how much memory is used.

Note, the CacheType NONE on the @Cache annotation should not be used to disable the cache, instead shared should be set to false.

See Introduction to Cache for details on these types.

How to refresh the cache

If the application knows the cache is out of date, it can clear, refresh or invalidate it programmatically.

If JPA 2.0 is used, this can be done using the JPA Cache interface:

em.getEntityManagerFactory().getCache().evictAll();

In JPA 1.0 this can be done using the EclipseLink IdentityMapAccessor:

((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().invalidateAll();

Both of these invalidate all of the objects in the cache. The cache can also be cleared, clearing the cache can cause object identity issues if any of the cached object is in use, so invalidating is safer. If you know that none of the cached objects are is use then you can just clear the cache.

((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().initializeAllIdentityMaps();

EclipseLink provides more cache API, see JpaCache and IdentityMapAccessor.

None of these actively refresh the cached objects, the objects will not be refreshed until next accessed.

To actively refresh an object the EntityManager refresh() API can be used. However this only refreshes a single object.

In JPA 2.0 a query hint can be used to trigger any query to refresh the cache.

Query query = em.createQuery("Select e from Employee e");
query.setHint("javax.persistence.cache.storeMode", "REFRESH");

In JPA 1.0 this can be done using the EclipseLink refresh query hint:

Query query = em.createQuery("Select e from Employee e");
query.setHint("eclipselink.refresh", "true");

Using the @Cache Annotation

You may define the @Cache annotation on the following:

  • @Entity
  • @MappedSuperclass;
  • the root of the inheritance hierarchy (if applicable).

If you define the @Cache annotation on an inheritance subclass, the annotation will be ignored. If you define the @Cache annotation on @Embeddable EclipseLink will throw an exception.

Example of @Cache Annotation

...
@Entity
@Cache(
  type=CacheType.SOFT, // Cache everything until the JVM decides memory is low.
  size=64000  // Use 64,000 as the initial cache size.
  expiry=360000,  // 6 minutes
  coordinationType=CacheCoordinationType.INVALIDATE_CHANGED_OBJECTS  // if cache coordination is used, only send invalidation messages.
)
public class Employee {
  ...
}

For more information on @Cache options and configuring caching, see Configuring Caching.

Caching in Clustered Environments

Caching in a clustered environment can have issues as changes made on one server will not be reflected on objects cached in other servers. For read-only objects, this is not an issue, but for objects that are frequently updated this can be an issue.

EclipseLink offers several solutions to this issue.

  • The cache can be disabled for the classes that frequently change.
  • Cache coordination can be used to broadcast changes between the servers in the cluster to update of invalidate changed objects.
  • Cache invalidation based on time-to-live or time-of-day.
  • Optimistic locking will prevent updates to stale objects, and trigger the objects to be invalidated in the cache.

See, How to enable cache coordination