Skip Headers
Oracle® Fusion Middleware Integration Guide for Oracle TopLink with Coherence Gird
11g Release 1 (11.1.1)

Part Number E16596-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

"JPA on the Grid" Configurations

This section includes information on the following configurations:

The sample code illustrated in the examples for each configuration can be obtained from: http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip.

Grid Cache

The TopLink Grid Coherence Grid Cache configuration uses Coherence as the TopLink shared (L2) cache. This brings the power of the Coherence data grid to JPA applications that rely on database hosted data that cannot be entirely preloaded into a Coherence cache for reasons including: extremely complex queries that exceed the feature set of Coherence Filters, third party database updates that create stale caches, reliance on native SQL queries, stored procedures or triggers, etc.

By using Coherence as its Grid cache, you can scale TopLink up into large clusters while avoiding the need to coordinate local Grid caches. Updates made to entities are available in all Coherence cluster members immediately, upon a transaction commit.

In general:

  • Primary key queries attempt to get entities first from Coherence and, if unsuccessful, will query the database, updating Coherence with query results. See "Reading Objects".

  • Non-primary key queries are executed against the database and the results checked against Coherence to avoid object construction costs for cached entities. Newly queried entities are put into Coherence.

  • Write operations update the database and, if successfully committed, updated entities are put into Coherence. See "Writing Objects".

See "Examples" for detailed examples.

Reading Objects

In the Coherence Grid Cache configuration, all read queries are directed to the database except primary key queries, which are performed against the Coherence cache first. Any cache misses will result in a database query.

All entities queried from the database are placed in the Coherence cache. This makes them immediately available to all members of the cluster which is valuable because, by default, TopLink leverages the cache to avoid constructing new entities from database results.

For each row resulting from a query, TopLink uses the primary key of the result row to query the corresponding entity from the cache. If the cache contains the entity then the entity is used and a new entity isn't built. This approach can greatly improve application performance, especially with a warmed cache, as reduces the cost of a query.

This figure illustrates a query in the Coherence Grid Cache configuration:

  1. Application issues a find query.

  2. For primary key queries, TopLink queries the Coherence cache first.

  3. If the object does not exist in the Coherence cache, TopLink queries the database.

    For all read queries except primary key queries, TopLink queries the database first.

  4. Read objects are put into the Coherence cache.

Writing Objects

In the Coherence Grid Cache configuration, TopLink performs all database writes (insert, update, delete). The Coherence cache is then updated to reflect the changes made to the database. TopLink offers a number of performance features when writing large amounts of data including: batch writing, parameter binding, stored procedure support, and statement ordering to ensure that database constraints are satisfied.

Figure 6 Writing and Persisting Objects

Description of Figure 6 follows
Description of "Figure 6 Writing and Persisting Objects"

This figure illustrates a query in the Coherence Grid Cache configuration:

  1. Application issues a commit query.

  2. TopLink updates the database.

  3. After a successful transaction, TopLink updates the Coherence cache.

Examples

The sample code illustrated in these examples can be obtained from: http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip.

In the cache configuration (coherence-cache-config.xml) define the cache and configure a wrapper serializer in order to support serialization of relationships, as shown in this example:

Example 4 Configuring the Cache

<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>
      <!--
        Configure a wrapper serializer to support serialization of relationships.
      -->
      <serializer>
        <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name>
      </serializer>
      <backing-map-scheme>
      <!-- 
        Backing map scheme with no eviction policy 
      -->
        <local-scheme>
          <scheme-name>unlimited-backing-map</scheme-name>
        </local-scheme>
      </backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes></cache-config>

To configure an entity to use the Coherence Grid cache, use the CoherencInterceptor class as shown in Example 5. This class intercepts all TopLink calls to the internal TopLink Grid cache and redirects them to Coherence.

Example 5 Configuring the Entity

import oracle.eclipselink.coherence.integrated.cache.CoherenceInterceptor;
import org.eclipse.persistence.annotations.Customizer;

@Entity
@CacheInterceptor(value = CoherenceInterceptor.class)
public class Employee {
...

In Example 6, TopLink performs the insert to create a new employee. Entities are persisted through the EntityManger and placed in the database.

Example 6 Inserting Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");

// Create an Employee with an Address and PhoneNumber
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = createEmployee();
em.persist(employee);
em.getTransaction().commit();           
em.close();

After a successful transaction, the Coherence cache is updated.

In Example 7, when TopLink finds an employee, the read query is directed to Coherence cache.

Example 7 Querying Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");

EntityManager em = emf.createEntityManager();
List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList();

for (Employee employee : employees) {
   System.err.println(employee);
   for (PhoneNumber phone : employee.getPhoneNumbers()) {
      System.err.println("\t" + phone);
   }
}

emf.close();

Grid Read

The TopLink Grid Read configuration should be used for entities that require fast access to large amounts of (fairly stable) data and must write changes synchronously to the database. In these entities, cache warming would typically be used to populate the Coherence cache but individual queries could be directed to the database if necessary.

In general:

  • Read operations get objects from the Coherence cache. Configuring a CacheLoader has no impact on JPQL queries. See "Reading Objects".

  • Write operations update the database and, if successfully committed, updated entities are put into Coherence. See "Writing Objects".

See "Examples" for detailed examples.

Reading Objects

In the Grid Read configuration, all read queries for an entity are directed to the Coherence cache. To reduce query processing time, TopLink Grid supports parallel processing of queries across the data grid. Coherence contains data in object form, avoiding the cost of database communication and object construction.

With the Grid Read configuration, if Coherence does not contain the Entity requested by find(...) then null is returned. However, if a CacheLoader is configured for the Entity's cache, Coherence will attempt to load the object from the database. This is only true for primary key queries.

Configuring a CacheLoader has no impact on JPQL queries translated to Coherence filters. When searching with a filter, Coherence will operate only on the set of Entities in the caches; the database will not be queried. However, it is possible on a query-by-query basis to direct a query to the database instead of to Coherence by using the oracle.eclipselink.coherence.integrated.querying.IgnoreDefaultRedirector class, as shown in following example:

query.setHint(QueryHints.QUERY_REDIRECTOR, new IgnoreDefaultRedirector());

Any objects retrieved by a database query will be added to the Coherence cache so they are available for subsequent queries. Because, by default, this configuration resolves all queries for an entity through Coherence, the Coherence cache should be warmed with all the data that is to be queried.

A CacheStore is not compatible with the Grid Read configuration because EclipseLink will be performing all database updates and then propagating the updated objects into Coherence. If you use a CacheStore, Coherence will attempt to write out the just-written objects again.

For complete information on using EclipseLink JPA query hints, refer to the EclipseLink documentation.

Figure 7 Reading Objects with a Query

Reading Objects
Description of "Figure 7 Reading Objects with a Query"

This figure illustrates a query in the Grid Read configuration:

  1. Application issues a JPQL query.

  2. TopLink executes a Filter on the Coherence cache.

  3. TopLink returns results from the Coherence cache only; the database is not queried.

Writing Objects

In the Grid Read configuration, TopLink performs all database writes directly (insert, update, delete). The Coherence caches are then updated to reflect the changes made to the database. TopLink offers a number of performance features when writing large amounts of data including: batch writing, parameter binding, stored procedure support, and statement ordering to ensure that database constraints are satisfied.

This approach offers the best of both worlds: database updates are performed efficiently and queries continue to be executed in parallel across the Coherence data grid, with the option of directing individual queries to the database.

Figure 8 Writing and Persisting Objects

Writing and Persisting Objects
Description of "Figure 8 Writing and Persisting Objects"

This figure illustrates a query in the Grid Read configuration:

  1. Application issues a commit query.

  2. TopLink updates the database.

  3. After a successful transaction, TopLink updates the Coherence cache.

Examples

The sample code illustrated in these examples can be obtained from: http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip.

In the cache configuration (coherence-cache-config.xml) define the cache and configure a wrapper serializer in order to support serialization of relationships, as shown in this example:

Example 8 Configuring the Cache

<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>*</cache-name>
      <scheme-name>eclipselink-distributed-readonly</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <distributed-scheme>
      <scheme-name>eclipselink-distributed-readonly</scheme-name>
      <service-name>EclipseLinkJPAReadOnly</service-name>
      <!--
        Configure a wrapper serializer to support serialization of relationships.
      -->
      <serializer>
        <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name>
      </serializer>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <internal-cache-scheme>
            <local-scheme />
          </internal-cache-scheme>
          <!-- 
            Define the cache scheme 
          -->
          <cachestore-scheme>
            <class-scheme>
              <class-name>oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheLoader</class-name>
              <init-params>
                <param-type>java.lang.String</param-type>
                <param-value>{cache-name}</param-value>
              </init-param>
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>employee</param-value>
                </init-param>
              </init-params>
            </class-scheme>
          </cachestore-scheme>
          <!-- 
            The read-only = true required when using a CacheLoader. If omitted, Coherence  will attempt to call CacheStore methods that are not available on CacheLoader. 
          -->
          <read-only>true</readonly>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes></cache-config>

To configure an entity to read through Coherence, use the CoherenceReadCustomizer as shown in the following example:

Example 9 Configuring the Entity

import oracle.eclipselink.coherence.integrated.config.CoherenceReadCustomizer;
import org.eclipse.persistence.annotations.Customizer;

@Entity
@Customizer(CoherenceReadCustomizer.class)
public class Employee {
...
}

In Example 10, TopLink performs the insert to create a new employee. If the transaction is successful, the new object is placed into Coherence under it's primary key.

Example 10 Inserting Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");// Create an Employee with an Address and PhoneNumber
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = createEmployee();
em.persist(employee);
em.getTransaction().commit();
em.close();

emf.close();

When finding an employee, the read query is directed to Coherence cache. The JPQL query is translated to Coherence filters, as shown in the following example.

Example 11 Querying Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");
EntityManager em = emf.createEntityManager();
List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList();
  for (Employee employee : employees) {
    System.err.println(employee);
      for (PhoneNumber phone : employee.getPhoneNumbers()) {
        System.err.println("\t" + phone);
      }
  }emf.close();

To get an object from the Coherence cache with a specific ID (key), use: em.find(Entity.class, ID). You can also configure a Coherence CacheLoader to query the database to find the object, if the cache does not contain one with the specified ID.

Grid Entity

The Grid Entity configuration should be used by applications that require fast access to large amounts of (fairly stable) data and that perform relatively few updates. This configuration can be combined with a Coherence CacheStore using write-behind to improve application response time by performing database updates asynchronously.

In general:

  • Read operations get objects from the Coherence cache. See "Reading Objects".

  • Write operations put objects into the Coherence cache. If a CacheStore is configured, TopLink also performs write operations on the database. See "Writing Objects".

See "Examples" for detailed examples.

Reading Objects

In the Grid Entity configuration, reading objects is identical to the Grid Read configuration. See "Reading Objects" for more information.

Writing Objects

In the Grid Entity configuration, all objects persisted, updated, or merged through an EntityManger will be put in the appropriate Coherence cache. To persist objects in a Coherence cache to the database, an EclipseLink CacheStore (oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheStore) must be configured for each cache.

You can also configure the CacheStore to use a "write behind" to asynchronously batch-write updated objects. See the Coherence Developer's Guide for more information.

Issues to be Aware of When Writing Objects

This section includes information on items you should be aware of when writing objects.

When using a CacheStore, Coherence assumes that all write operations succeed and will not inform TopLink of a failure. This could result in the Coherence cache differing from the database. You cannot use optimistic locking to protect against data corrupts that may occur if the database is concurrently modified by Coherence and a third-party application.

Because each class may be in a separate cache, Coherence may not issue the delete calls to the stores in the required order or with correct timing. As a result, constraint compliance is not guaranteed and write operations could fail with the following error:

org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.BatchUpdateException: ORA-02292: integrity constraint violated - child record found
Error Code: 2292

The database foreign key restraints should be reviewed and may need to be removed.

Figure 9 Writing and Persisting Objects

Writing and persisting objects.
Description of "Figure 9 Writing and Persisting Objects"

This figure illustrates a query in the Grid Entity configuration:

  1. Application issues a commit.

  2. TopLink directs all queries to update the Coherence cache.

  3. By configuring a Coherence CacheStore (optional), TopLink will also update the database.

Examples

In the cache configuration (coherence-cache-config.xml) configure a wrapper serializer in order to support serialization of relationships, as shown in this example:

The sample code illustrated in these examples can be obtained from: http://www.oracle.com/technology/products/ias/toplink/doc/11110/grid/guide/TopLinkGrid-Examples.zip.

Example 12 Configuring the Cache

<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>*</cache-name>
      <scheme-name>eclipselink-distributed-readwrite</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <distributed-scheme>
      <scheme-name>eclipselink-distributed-readwrite</scheme-name>
      <service-name>EclipseLinkJPAReadWrite</service-name>
      <!--
        Configure a wrapper serializer to support serialization of relationships.
      -->
      <serializer>
        <class-name>oracle.eclipselink.coherence.integrated.cache.WrapperSerializer</class-name>
      </serializer>
      <backing-map-scheme>
       <read-write-backing-map-scheme>
        <internal-cache-scheme>
          <local-scheme />
          </internal-cache-scheme>
           <!-- 
             Define the cache scheme 
           -->
            <cachestore-scheme>
              <class-scheme>
                <class-name>oracle.eclipselink.coherence.integrated.EclipseLinkJPACacheStore</class-name>
                <init-params>
                  <init-param>
                    <param-type>java.lang.String</param-type>
                    <param-value>{cache-name}</param-value>
                  </init-param>
                  <init-param>
                    <param-type>java.lang.String</param-type>
                    <param-value>employee</param-value>
                  </init-param>
                </init-params>
              </class-scheme>
            </cachestore-scheme>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
  </caching-schemes>
</cache-config>

To configure an entity to read through Coherence, use the CoherenceReadWriteCustomizer as shown in the following example:

Example 13 Configuring the Entity

import oracle.eclipselink.coherence.integrated.config.CoherenceReadWriteCustomizer;
import org.eclipse.persistence.annotations.Customizer;

@Entity
@Customizer(CoherenceReadWriteCustomizer.class)
public class Employee {
...
}

In Example 14, TopLink performs the insert to create a new employee. Entities are persisted through the EntityManger and placed in the appropriate Coherence cache.

Example 14 Persisting Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");

// Create an Employee with an Address and PhoneNumber
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = createEmployee();
em.persist(employee);
em.getTransaction().commit();           
em.close();

When finding an employee, the read query is directed to Coherence cache, as shown in the following example.

Example 15 Querying Objects

EntityManagerFactory emf = Persistence.createEntityManagerFactory("employee");

EntityManager em = emf.createEntityManager();
List<Employee> employees = em.createNamedQuery("Employee.findByLastNameLike").setParameter("lastName", "Smit%").getResultList();

for (Employee employee : employees) {
   System.err.println(employee);
   for (PhoneNumber phone : employee.getPhoneNumbers()) {
      System.err.println("\t" + phone);
   }
}

emf.close();

To get an object from the Coherence cache with a specific ID (key), use: em.find(Entity.class, ID). You can also configure a Coherence CacheLoader to query the database to find the object, if the cache does not contain one with the specified ID.