JPA cache

JPA (Java Persistence) implementations use a level 2 cache, which is a cache behind the session cache (aka unit of work cache). This cache is typically used when using EntityManager’s find operation or querying for entities using the primary key. This cache is also used to initialize collection members after loading up an entities collection.

JPA cache in an application server cluster such as that of Weblogic

When the JPA application is deployed on a single node of an application server, and there is no out of band access to the database, cache is really a boon. However, as soon as there are external writes to the database, the cache invalidation problem becomes a problem. The external write could be either some other application writing to the database or the application itself deployed in an application cluster scenario.


For example, consider an application which manages car distributorship. The application queries for the cars in the inventory and on sale, updates the inventory as sold. When such a query is made, it is possible that the Car entity may be loaded into the L2 cache of the JPA implementation. Now when the purchase operation updates one node in the cluster and if it is not refreshed or invalidated in the other node, then the application is potentially dealing with stale data in the cache.


To handle such situation obviously some cache synchronization techniques need to be employed. In this entry, I will be documenting three strategies that can be used with Oracle Toplink working in a Weblogic cluster environment

<!--[if !supportLists]-->1. <!--[endif]-->Disable the cache

<!--[if !supportLists]-->2. <!--[endif]-->Use Toplink Cache Coordination

<!--[if !supportLists]-->3. <!--[endif]-->Use Toplink Grid (Oracle Coherence integration)

Disabling the Toplink L2 cache

L2 cache can be disabled per entity or as a whole. To disable the cache for all entities, add the following property to the persistence.xml

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


To disable cache per entity, you will need to use the following entry in the eclipselink-orm.xml

<cache shared="false" />


For example


<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings version="2.1"

xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<entity class="mypackage.MyEntity">

<cache shared="false" />

</entity>

</entity-mappings>


However, please note the bug in the current implementation - ​​https://bugs.eclipse.org/bugs/show_bug.cgi?format=multiple&id=304868​​. The work around suggested in this bug needs to be done.

Use Toplink Cache Coordination

Cache coordination is a mechanism of Eclipslink (Toplink) which allows the JPA caches on the individual nodes to communicate and synchronize the changes. The communication itself could be done through the following transports –

<!--[if !supportLists]-->1. <!--[endif]-->JMS

<!--[if !supportLists]-->2. <!--[endif]-->RMI

<!--[if !supportLists]-->3. <!--[endif]-->CORBA


JMS also allows for asynchronous coordination.


The following strategies can be employed to synchronize the changes in the cache –

<!--[if !supportLists]-->1. <!--[endif]-->SEND_OBJECT_CHANGES – This is the default and sends update events only for changes in the attributes of an entity. New object creations (for example adding a new member to a collection) is not propagated

<!--[if !supportLists]-->2. <!--[endif]-->INVALIDATE_CHANGED_OBJECTS – This option invalidates the entity on the peer cache whenever it changes.

<!--[if !supportLists]-->3. <!--[endif]-->SEND_NEW_OBJECTS_WITH_CHANGES – This option adds to the first option to also send newly created entities. This option takes care of refreshing additions of a member to a collection.

<!--[if !supportLists]-->4. <!--[endif]-->NONE – No updates sent


To set up cache coordination, two configurations need to be done –

<!--[if !supportLists]-->1. <!--[endif]-->Set up the coordination transport

<!--[if !supportLists]-->2. <!--[endif]-->Set up the coordination type for the entities


To set up the cache coordination transport, edit the persistence.xml and add the following properties –

<property name="eclipselink.cache.coordination.protocol" value="rmi"/>

<property name="eclipselink.cache.coordination.rmi.multicast-group" value="231.1.1.1"/>

<property name="eclipselink.cache.coordination.rmi.multicast-group.port" value="9872"/>

<property name="eclipselink.cache.coordination.jndi.user" value="weblogic"/>

<property name="eclipselink.cache.coordination.jndi.password" value="Welcome1"/>

<property name="eclipselink.cache.coordination.propagate-asynchronously" value="false"/>

<property name="eclipselink.cache.coordination.naming-service" value="jndi"/>

<property name="eclipselink.cache.coordination.rmi.url" value="t3://localhost:7004"/>

<property name="eclipselink.cache.coordination.packet-time-to-live" value="4"/>


This sets up the configuration for RMI. Please note that the RMI URL can point to any of the Weblogic managed servers since the JNDI tree is replicated in a cluster. Alternatively, the “port” can also be left out.


To set up the cache coordination type, edit the eclipselink-orm.xml and add the following –

<cache coordination-type="INVALIDATE_CHANGED_OBJECTS" />


For example –

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings version="2.1"

xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<entity class="mypackage.MyEntity">

<cache coordination-type="INVALIDATE_CHANGED_OBJECTS" />

</entity>

</entity-mappings>


However, please note the bug in the current implementation –

​https://bugs.eclipse.org/bugs/show_bug.cgi?id=312909​​. The work around suggested in this bug needs to be done.

Use Toplink Grid

Toplink Grid is the integration of Toplink with Oracle Coherence. Toplink Grid is part of Active Cache which also includes Coherence Web.


Toplink Grid provides three strategies to integrate a JPA (Toplink) application with Coherence –

<!--[if !supportLists]-->1. <!--[endif]-->Grid Cache

<!--[if !supportLists]-->2. <!--[endif]-->Grid Read

<!--[if !supportLists]-->3. <!--[endif]-->Grid Write


Grid Cache is the simplest and the least intrusive for a vanilla JPA application. This basically ties the L2 cache of Toplink with Coherence so that every read from JPA cache results in a get from Coherence and similarly, every write to JPA cache results in a put to Coherence.


Grid Read and Grid Write require code changes and allow Toplink to read through or write through Coherence. However with this feature, the full benefit of Data Grid can be realized.


In this entry, the configurations for Grid Cache is described. The following steps need to be performed for configuring –

<!--[if !supportLists]-->1. <!--[endif]-->Create Coherence Cache configuration and refer to this from the JPA application

<!--[if !supportLists]-->2. <!--[endif]-->Configure Coherence Cluster and refer to this from the JPA application

<!--[if !supportLists]-->3. <!--[endif]-->Set up related shared libraries in Weblogic and refer to these libraries from the JPA application

<!--[if !supportLists]-->4. <!--[endif]-->Configure JPA entities to use Grid Cache

Coherence Cache configuration

Create coherence-cache-config.xml file in some known location say D:\ and add the Cache configuration to this file.

<?xml version="1.0"?>

<!DOCTYPE cache-config SYSTEM "cache-config.dtd">

<cache-config>

<caching-scheme-mapping>

<cache-mapping>

<cache-name>*</cache-name>

<scheme-name>eclipselink-distributed</scheme-name>

</cache-mapping>

</caching-scheme-mapping>

<caching-schemes>

<distributed-scheme>

<scheme-name>eclipselink-distributed</scheme-name>

<service-name>EclipseLinkJPA</service-name>

<serializer>

<class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name>

</serializer>

<backing-map-scheme>

<local-scheme>

<high-units> 10000 </high-units>

<eviction-policy> LFU </eviction-policy>

</local-scheme>

</backing-map-scheme>

<autostart>true</autostart>

</distributed-scheme>

</caching-schemes>

</cache-config>


After this create a JAR file for the above file and add the JAR file as a shared library (target to all relevant servers) in Weblogic console and refer to this shared library from MyApp.ear\META-INF\weblogic-application.xml as follows –

<library-ref>

<library-name>coherence-cache-config</library-name>

</library-ref>

Coherence cluster configuration

In Weblogic console, find “Coherence Clusters” under Services. Create a new Coherence Cluster. Specify the following –

Name: CoherenceCluster

Unicast Listen Address: localhost

Unicast Listen Port: Unique port number

Unicast Port Auto Adjust: true

Multicast Listen Address: 231.1.1.1

Multicast Listen Port: Unique port number


Refer to the above Coherence Cluster in MyApp.ear\META-INF\weblogic-application.xml as follows –

<coherence-cluster-ref>

<coherence-cluster-name>CoherenceCluster</coherence-cluster-name>

</coherence-cluster-ref>

Related Library configurations

Create shared libraries (target to all relevant servers) for the following in Weblogic console –

<!--[if !supportLists]-->1. <!--[endif]-->D:\Oracle\Middleware11.1.1.3\wlserver_10.3\common\deployable-libraries\active-cache-1.0.jar

<!--[if !supportLists]-->2. <!--[endif]-->D:\Oracle\Middleware11.1.1.3\wlserver_10.3\common\deployable-libraries\toplink-grid-1.0.jar

<!--[if !supportLists]-->3. <!--[endif]-->D:\Oracle\Middleware11.1.1.3\coherence_3.5\lib\coherence.jar

Refer to the above shared libraries from MyApp.ear\META-INF\weblogic-application.xml. Add the following elements

<library-ref>

<library-name>active-cache</library-name>

</library-ref>

<library-ref>

<library-name>toplink-grid</library-name>

</library-ref>

<library-ref>

<library-name>coherence</library-name>

</library-ref>


Note that reference to the cache configuration should be above reference to coherence.

Configure JPA entities to use Grid Cache

To set up the Grid Cache, edit the eclipselink-orm.xml


For example –

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings version="2.1"

xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<entity class="mypackage.MyEntity">

<customizer class="oracle.eclipselink.coherence.integrated.config.GridCacheCustomizer"/>

</entity>

</entity-mappings>

Running Coherence

To start Coherence Server, run the following



D:\>java -server -Xms512m -Xmx512m -javaagent:D:\Oracle\Middleware11.1.1.3\modules\org.eclipse.persistence_1.0.0.0_2-0.jar -cp D:\Oracle\Middleware11.1.1.3\cohe

rence_3.5\lib\coherence.jar;D:\Oracle\Middleware11.1.1.3\modules\javax.persistence_1.0.0.0_1-0-2.jar;D:\Oracle\Middleware11.1.1.3\modules\com.oracle.toplink_1.0

.0.0_11-1-1-3-0.jar;D:\Oracle\Middleware11.1.1.3\modules\com.oracle.toplinkgrid_1.0.0.0_11-1-1-3-0.jar;MyApp.jar -Dtangosol.coherence.cacheconfig=d:\coherence-cache-config.xml

-Dtangosol.coherence.management.remote=true -Dtangosol.coherence.distributed.localstorage=true -Dtangosol.coherence.clusterport=7777 -Dtango

sol.coherence.clusteraddress=231.1.1.1 com.tangosol.net.DefaultCacheServer