9 Interacting with the Cache and the Database

In this exercise, you will create and configure an Oracle Coherence cache in Eclipse. It highlights the use of the Coherence CacheStore, ContinuousQueryCache, IdentityExtractor, and Filter APIs.

In this exercise you will create these items:

This chapter contains the following sections:

9.1 Introduction

A Coherence cache is a collection of data objects that acts as an intermediary between the database and the client applications. Database data can be loaded into a cache and made available to different applications. Thus, Coherence caches reduce load on the database and provide faster access to database data.

Coherence caches provide higher availability through database isolation and data replication. Modifications made to a cache can be synchronized with the database whenever the database is available. Even if the database or an application server node is not available, database updates are still reliable due to the lazy load and lazy write mechanism used by a Coherence cache and due to the failover and fail back provided by Coherence.

Coherence caches provide distributed processing not only across a cluster of application server nodes but also across the data objects in the cache, because data modification operations can be performed on the data objects.

Coherence also provides event-based processing. The state of data objects in a cache can be monitored and actions invoked on other processes such as the start of a business process execution language (BPEL) process.

Coherence supports different types of caches:

  • Replicated caches, where data is replicated to each of the application server nodes in the cluster. This type of cache is recommended if faster read access is required but not suitable for write operations, because data must be written to each of the nodes. The drawback of replicated caches is that they require a large amount of memory because every node has a copy of every object.

  • Distributed (or partitioned) caches, where data is distributed (load-balanced) across different nodes. Failover is implemented in a distributed cache using backups, which are also distributed across the cluster nodes.

Coherence is implemented by using services such as the cluster service, the distributed cache service, and the replicated cache service. Whichever type of cache is used, an application uses the same API to access and store data.

A cache configuration deployment descriptor is used to configure a cache. The root element of the cache configuration file is cache-config. Cache names and name patterns are mapped to cache types in the caching-scheme-mapping element using the subelement cache-mapping. Cache types are defined in the caching-schemes element. Table 9-1 describes some of the cache types commonly used by Coherence.

Table 9-1 Descriptions of Cache Types

Cache Type Description

distributed scheme

Defines a distributed cache in which data is stored across a cluster of nodes.

replicated scheme

Defines a cache in which cache entries are replicated across all the cluster nodes.

read-write-backing-map scheme

Defines a map, which provides a cache of a persistent store such as a relational database.

external scheme

Defines an external cache such as a disk.

class scheme

Defines a custom cache implementation, which is required to implement the java.util.Map interface.


9.2 Creating a Cache Application

This section describes how to create and run an application that puts data into the cache and retrieves it.

  1. Create an Application that Constructs a Cache

  2. Create a Cache Configuration File

  3. Create a Run Configuration for the Application

  4. Create the Cache Server Start-Up Configuration

  5. Run the Cache Creation Application

9.2.1 Create an Application that Constructs a Cache

To create a Java class that constructs a Coherence cache:

  1. Create a project in Eclipse.

    1. Use the JPA perspective in Eclipse to create a JPA Project called Interaction. Select the JPAConfiguration you created in Chapter 8, "Using JPA with Coherence."

    2. In the JPA Facet page, ensure that EclipseLink 2.5.x appears in the Platform field. Ensure that Coherence12.1.3, Oracle Database Driver, and TopLink are selected under User Libraries. In the Connection field, select the connection you created in "Configure the Project for JPA" (XE_HR), from the Connection drop down list. Click the Connect link to connect to the Oracle Database if necessary. (Note, this assumes that the database connection that you created is still running.) Select Add Driver Library to Build Path and select Oracle Database Driver Default from the drop-down list. Click Next.

    3. In the Coherence page, ensure that Coherence12.1.3, Oracle Database Driver, and TopLink are selected. Click Finish.

  2. Create a Java class, CoherenceCache, that will be used to create a Coherence cache. Include a main method in the class. See "Creating a Java Class" for detailed information on creating a class.

    1. Create a cache in the CoherenceCache Java class. Import the CacheFactory class and the NamedCache interface.

      import com.tangosol.net.CacheFactory; 
      import com.tangosol.net.NamedCache;
      
    2. Create the cache (NamedCache) instance by using the CacheFactory.getCache method. Use the cache name VirtualCache, which is mapped to a distributed caching scheme.

      NamedCache cache = CacheFactory.getCache ( "VirtualCache");
      
    3. A NamedCache is a java.util.Map instance that holds resources that are shared across nodes in a cluster. Add a cache entry by using the put method.

      cache.put (key, "Hello Cache");
      
    4. Retrieve a cache entry by using the get method.

      System.out.println((String)cache.get("hello"));
      

      Example 9-1 illustrates a possible implementation of CoherenceCache class. You can copy the code to the CoherenceCache file in Eclipse.

      Example 9-1 Implementation of a Coherence Cache

      package com.oracle.handson;
      
      import com.tangosol.net.CacheFactory; 
      import com.tangosol.net.NamedCache;
      
      public class CoherenceCache 
          {
          NamedCache cache;
          public CoherenceCache() 
          {
          }
          public void putCache()
              {
              cache = CacheFactory.getCache ( "VirtualCache"); 
              String key = "hello"; 
              cache.put (key, "Hello Cache"); 
              }
             
             public void retrieveCache()
                 {
                 System.out.println((String)cache.get("hello"));
                 }
             
              public static void main (String [] args) 
              {
              CoherenceCache cache = new CoherenceCache(); 
              cache.putCache();
              cache.retrieveCache();
              }
      }
      

9.2.2 Create a Cache Configuration File

In the Project Explorer, rename the coherence-cache-config.xml cache configuration file to be cache-config.xml. Open the file in the Eclipse Editor.

In the cache configuration file:

  • Define mappings for cache names and naming patterns with the cache-mapping elements in the caching-scheme-mapping element.

  • Map the cache name VirtualCache to cache type distributed-eclipselink.

  • Define the distributed caching scheme with the distributed-scheme element using the EclipseLinkJPA service.

The cache configuration file is illustrated in Example 9-2. Copy the contents of this example to the cache-config.xml.

Example 9-2 Cache Configuration File

<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config http://xmlns.oracle.com/coherence/coherence-cache-config/1.2/coherence-cache-config.xsd">
 
  <defaults>
    <serializer system-property="tangosol.coherence.serializer"/>
    <socket-provider system-property="tangosol.coherence.socketprovider"/>
  </defaults>
    <caching-scheme-mapping>
        
        <cache-mapping>
            <cache-name>VirtualCache</cache-name>
            <scheme-name>distributed-eclipselink</scheme-name>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <!--
        Default Distributed caching scheme.
        -->
        <distributed-scheme>
            <scheme-name>distributed-eclipselink</scheme-name>
            <service-name>EclipseLinkJPA</service-name>
            <backing-map-scheme>
                <class-scheme>
                    <scheme-ref>default-backing-map</scheme-ref>
                </class-scheme>
            </backing-map-scheme>
         <autostart>true</autostart>
        </distributed-scheme>
         <class-scheme>
            <scheme-name>default-backing-map</scheme-name>
            <class-name>com.tangosol.util.SafeHashMap</class-name>
         </class-scheme>
 </caching-schemes>
</cache-config>

9.2.3 Create a Run Configuration for the Application

Create a run configuration for the application to add the cache configuration file as a run-time Java option.

  1. Right click CoherenceCache.java in the Project Explorer and choose Run As then Run Configurations. In the Run Configurations dialog box, click the New launch configuration icon.

  2. Enter CoherenceCacheServer in the Name field. Ensure that Interaction is in the Project field and com.oracle.handson.CoherenceCache is in the Main class field.

  3. In the Coherence tab, enter the path to the cache configuration file, C:\home\oracle\workspace\Interaction\src\cache-config.xml. Select the Enabled (cache server) button. Enter a unique value, such as 3155, in the Cluster port field. Click Apply.

    The Classpath tab should look similar to Figure 9-1.

    Figure 9-1 Classpath for the CoherenceCacheServer Executable

    Classpath for the CoherenceCache Program
    Description of "Figure 9-1 Classpath for the CoherenceCacheServer Executable"

9.2.4 Create the Cache Server Start-Up Configuration

To create a cache sever start-up configuration for the Interaction project:

  1. Right click the Interaction project and select Properties. In the Properties for Interact dialog box, select Java Build Path. In the Order and Export tab, the Interaction project, the JRE, Coherence12.1.3, TopLink, and the Oracle Database Driver Default libraries should be present. Ensure that they are all selected. The Order and Export tab should look similar to Figure 9-2.

    Figure 9-2 Order and Export Tab for Libraries for the Java Build Path

    Order and Export for Libraries for the Java Build Path
    Description of "Figure 9-2 Order and Export Tab for Libraries for the Java Build Path "

  2. Edit the JPA cache server start-up configuration (JPAServer) that you created in Chapter 8, "Using JPA with Coherence".

    1. Right click the Interaction project and select Run As then Run Configurations. In the Main tab click Browse and select the Interaction project from the Project Selection dialog box.

    2. In the General tab of the Coherence tab, replace the name and path of the configuration file with C:\home\oracle\workspace\Interaction\src\cache-config.xml.

    3. In the Classpath tab, remove the JPA (default classpath) folder if it appears. Click Add Project to add the Interaction project. The Classpath tab should look similar to Figure 9-3.

      Figure 9-3 Classpath for the Interaction Project Cache Server

      The Classpath tab for the Interact Project Cache Server
      Description of "Figure 9-3 Classpath for the Interaction Project Cache Server"

    4. In the Shared file field of the Common tab, click Browse to select the Interaction project. Click Apply, then Close.

9.2.5 Run the Cache Creation Application

To run the cache creation application CoherenceCache.java:

  1. Stop any running cache servers. See "Stopping Cache Servers" for more information.

  2. Run the JPAServer to start the cache server.

  3. Right-click the Coherence application CoherenceCache.java and click Run As then Run Configurations. Select the CoherenceCacheServer configuration and click Run. The Eclipse console window displays the output:

    • The operational configuration is loaded from the tangosol-coherence.xml file. This file specifies the operational and run-time settings used by Coherence for its clustering, communication, and data management services.

    • The cache configuration is loaded from the cache-config.xml file.

    • A new cluster is created and the DistributedCache service joins the cluster.

    • The output of the CoherenceCache.java program, Hello Cache is displayed.

    Example 9-3 Output of the Coherence Cache Application

    ...
    2013-12-20 11:41:53.821/0.930 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Interaction/src/cache-config.xml"
    2013-12-20 11:41:54.451/1.560 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
    2013-12-20 11:41:55.672/2.781 Oracle Coherence GE 12.1.3.0.0 <D4> (thread=main, member=n/a): TCMP bound to /10.159.165.75:8090 using SystemDatagramSocketProvider
    2013-12-20 11:41:56.333/3.442 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=Cluster, member=n/a): Failed to satisfy the variance: allowed=16, actual=20
    ...
    2013-12-20 11:41:57.384/4.493 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=NameService:TcpAcceptor, member=2): TcpAcceptor now listening for connections on 10.159.165.75:8090.3
    2013-12-20 11:41:57.744/4.853 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=DistributedCache:EclipseLinkJPA, member=2): Service EclipseLinkJPA joined the cluster with senior service member 1
    Hello Cache
    

9.3 Creating a Database Cache

In this section, create a cache backed by Oracle Database. This is also referred to as an Oracle Database cache.

  1. Create an Oracle Database Cache

  2. Create a Class to Define a Custom Cache Store

  3. Modify the Cache Configuration File

  4. Create a Class to Construct the Database Cache

  5. Run the Database Cache Application

9.3.1 Create an Oracle Database Cache

To use SQL*Plus and the Oracle Database to create an Oracle Database cache follow these steps. You must have the database installed on your system.

  1. Invoke SQL*Plus.

    Navigate to Start then All Programs then <Oracle Database Home> (for example, Oracle-OraDB12Home1) then Application Development, and then SQL Plus.

  2. Connect as hr user with hr as the password.

    connect hr/hr;
     
    
  3. Create an Oracle Database table.

    Open a text editor and copy the following SQL code. Save it as a file named dbscript.sql in the /home/oracle/workspace/ folder.

    Example 9-4 SQL Script for Creating a Database Table

    CREATE TABLE HR.CATALOG(id VARCHAR(25) PRIMARY KEY, value VARCHAR(96)); 
    INSERT INTO HR.CATALOG VALUES('catalog1', 'Tuning Undo Tablespace');
    INSERT INTO HR.CATALOG VALUES('catalog2', 'Tuning Your View Objects');
    
  4. Run the SQL script.

    Example 9-5 illustrates the output from the script.

    Example 9-5 Running the SQL Script for Creating a Database Table

    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
     
    Enter user-name: system
    Enter password:
    Last Successful login time: Thu Dec 19 2013 11:35:04 -08:00
     
    Connected to:
    Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
    
    SQL> connect hr/hr;
    Connected.
    SQL> @/home/oracle/workspace/dbscript.sql
    
    Table created
    
    1 row created
    
    1 row created
    

9.3.2 Create a Class to Define a Custom Cache Store

To create a Java class that connects to the database and retrieves table data:

  1. Create a Java class DBCacheStore in the Interaction project in Eclipse. See "Creating a Java Class" for detailed information.

  2. Create the code to connect to the database and get table data.

    Example 9-6 illustrates a possible implementation of the DBCacheStore class. Copy the code to the DBCacheStore application in the Eclipse IDE. The DBCacheStore application uses Java Database Connectivity (JDBC) to access Oracle Database, but you could use another mechanism, such as Hibernate or Java Data Objects (JDO), instead.

    Example 9-6 Database Cache Store Implementation

    package com.oracle.handson;
    
    import com.tangosol.net.cache.CacheStore;import com.tangosol.util.Base;
    
    import java.sql.DriverManager;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    
    public class DBCacheStore
    
            extends Base
            implements CacheStore {
        
            protected Connection m_con;
            protected String m_sTableName;
            private static final String DB_DRIVER   = "oracle.jdbc.OracleDriver";
    
                
                private static final String DB_URL      = "jdbc:oracle:thin:@localhost:1521:orcl";
                private static final String DB_USERNAME = "hr";
                private static final String DB_PASSWORD = "hr";
        
        public DBCacheStore(String sTableName)
            {
            m_sTableName = sTableName;
    
            configureConnection();        }
        protected void configureConnection()
            {
            try
                {
                Class.forName("oracle.jdbc.OracleDriver");
                m_con = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD);
                m_con.setAutoCommit(true);
                }
            catch (Exception e)
                {
                throw ensureRuntimeException(e, "Connection failed");
                }
            }
    
        public String getTableName()        {
            return m_sTableName;
            }
    
        public Connection getConnection()
            {
            return m_con;
            }
    
        public Object load(Object oKey)
            {
            Object     oValue = null;
            Connection con    = getConnection();
            String     sSQL   = "SELECT id, value FROM " + getTableName()
                        + " WHERE id = ?";
            try
                {
                PreparedStatement stmt = con.prepareStatement(sSQL);
    
                stmt.setString(1, String.valueOf(oKey));
                ResultSet rslt = stmt.executeQuery();
                if (rslt.next())
                    {
                    oValue = rslt.getString(2);
                    if (rslt.next())
                        {
                        throw new SQLException("Not a unique key: " + oKey);
                        }                }
                stmt.close();
                }
            catch (SQLException e)
                {
                throw ensureRuntimeException(e, "Load failed: key=" + oKey);
                }
            return oValue;
            }
    
          public void store(Object oKey, Object oValue)
            {
            Connection con     = getConnection();
            String     sTable  = getTableName();
            String     sSQL;
            
            if (load(oKey) != null)
                {
                
                sSQL = "UPDATE " + sTable + " SET value = ? where id = ?";
                }
            else
                {
                
                sSQL = "INSERT INTO " + sTable + " (value, id) VALUES (?,?)";
                }
            try
                {
                PreparedStatement stmt = con.prepareStatement(sSQL);
                int i = 0;
                stmt.setString(++i, String.valueOf(oValue));
                stmt.setString(++i, String.valueOf(oKey));
                stmt.executeUpdate();
                stmt.close();
                }
            catch (SQLException e)
                {
                throw ensureRuntimeException(e, "Store failed: key=" + oKey);
                }
            }
        public void erase(Object oKey)
            {
            Connection con  = getConnection();
            String     sSQL = "DELETE FROM " + getTableName() + " WHERE id=?";
            try
                {
                PreparedStatement stmt = con.prepareStatement(sSQL);
    
                stmt.setString(1, String.valueOf(oKey));
                stmt.executeUpdate();
                stmt.close();
                }
            catch (SQLException e)
                {
                throw ensureRuntimeException(e, "Erase failed: key=" + oKey);
                }
            }
        public void eraseAll(Collection colKeys)
            {
            throw new UnsupportedOperationException();
            }
    
        public Map loadAll(Collection colKeys)        {
            throw new UnsupportedOperationException();
            }
    
        public void storeAll(Map mapEntries)
            {
            throw new UnsupportedOperationException();
            }
       
        public Iterator keys()
            {
            Connection con  = getConnection();
            String     sSQL = "SELECT id FROM " + getTableName();
            List       list = new LinkedList();
            
            try
                {
                PreparedStatement stmt = con.prepareStatement(sSQL);
                ResultSet         rslt = stmt.executeQuery();
                while (rslt.next())
                    {
                    Object oKey = rslt.getString(1);
                    list.add(oKey);
                    }
                stmt.close();
                }
            catch (SQLException e)
                {
                throw ensureRuntimeException(e, "Iterator failed");
                }
    
            return list.iterator();
            }
        
        }
    

9.3.3 Modify the Cache Configuration File

Modify the cache configuration file (cache-config.xml) that you created earlier for the database cache. To connect a cache to a database, you must configure the cachestore-scheme element with a custom class that implements either the com.tangosol.net.cache.CacheLoader or com.tangosol.net.cache.CacheStore interface.

Replace the code in the existing cache-config.xml file in Eclipse with the cache configuration code for the database cache in Example 9-7.

Example 9-7 Database Cache Configuration File

<?xml version="1.0" encoding="UTF-8" ?>
<cache-config>
    <caching-scheme-mapping>
        
  <!-- 
    Caches with names that start with 'DBBacked' will be created 
    as distributed-db-backed.   
    -->
  <cache-mapping>
   <cache-name>DBBacked*</cache-name>
   <scheme-name>distributed-db-backed</scheme-name>
  </cache-mapping>
 </caching-scheme-mapping>
 <caching-schemes>
  <!-- 
    DB Backed Distributed caching scheme.
    -->
  <distributed-scheme>
   <scheme-name>distributed-db-backed</scheme-name>
   <service-name>DistributedCache</service-name>
   <backing-map-scheme>
    <read-write-backing-map-scheme>
     <internal-cache-scheme>
      <class-scheme>
       <class-name>com.tangosol.util.ObservableHashMap</class-name>
      </class-scheme>
     </internal-cache-scheme>
     <cachestore-scheme>  
      <class-scheme> 
       <class-name>com.oracle.handson.DBCacheStore</class-name> 
       <init-params>   
        <init-param> 
         <param-type>java.lang.String</param-type> 
         <param-value>CATALOG</param-value> 
        </init-param> 
       </init-params> 
      </class-scheme> 
     </cachestore-scheme> 
     <read-only>false</read-only>
     <!--
        To make this a write-through cache just change the value below to 0 (zero)
        -->
     <write-delay-seconds>0</write-delay-seconds>
    </read-write-backing-map-scheme>
   </backing-map-scheme>
   <autostart>true</autostart>
  </distributed-scheme>
 </caching-schemes>
</cache-config>

In the cache configuration file, you have done the following:

  • Defined a cache name pattern DBBacked*, which is mapped to a distributed caching scheme distributed-db-backed.

  • Specified the CacheStore scheme in the distributed scheme using the class coherence.DBCacheStore, which implements the CacheStore interface.

  • Specified for the DBCacheStore class an init parameter for the database table that is at the back end of the cache. The table name is specified in the init-param element. The DBCacheStore class performs database operations such as reading and writing cache entries.

  • Specified a read-write-backing-map-scheme as the backing map. This scheme defines a backing map, which provides a size-limited cache of a persistent store. Here, by setting the write-delay-seconds parameter to 0, you specify the write-through mechanism.

    Table 9-2 describes the types of read/write caching that you can use with Coherence.

Table 9-2 Types of Read/Write Caching Supported by Coherence

Types of Read/Write Caching Action

read-through

A cache entry is read into a cache from the database when required and made available to an application.

write-through

Updates to cache entries are synchronized with the database without a delay.

refresh-ahead

Cache entries are refreshed periodically.

write-behind

Updates to cache entries are asynchronously written to a database after a delay specified in the write-delay-seconds element in the cache configuration file.


9.3.4 Create a Class to Construct the Database Cache

Create a Java class DatabaseCache for the database cache in the Interaction project in Eclipse. The class must contain a main method. See "Creating a Java Class" for detailed information.

In the class file, provide the code to add a cache entry, query a database cache, and retrieve a cache entry. Add the following methods: createCache(), addEntry(), retrieveEntry(), eraseEntry(), and queryCache(). Example 9-8 illustrates a possible implementation.

Example 9-8 Implementation for the DatabaseCache Class File

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.net.cache.ContinuousQueryCache;
import com.tangosol.util.Filter;
import com.tangosol.util.extractor.IdentityExtractor;
import com.tangosol.util.filter.LikeFilter;

import java.util.HashSet;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class DatabaseCache {
    NamedCache cache;
    public DatabaseCache() {
    }

    public void createCache() 
         {
         cache = CacheFactory.getCache("DBBackedCache");
         }

    public void addEntry() 
        {
        cache.put(new String("catalog3"), new String("Tuning Grid Management"));
        cache.put(new String("catalog4"), new String("Tuning Coherence"));
        cache.put(new String("catalog5"), new String("Tuning Database"));
        }

    public void retrieveEntry() 
        {
        System.out.println((String) cache.get( "catalog3"));
        }

    public void eraseEntry() 
       {
       cache.remove(new String("catalog3"));
       }

    public void queryCache() 
       {
       Filter filter = new LikeFilter(IdentityExtractor.INSTANCE, "Tuning%", '\\', true);
       HashSet hashSet=new HashSet();
       hashSet.add(new String("catalog3"));
       hashSet.add(new String("catalog4"));
       hashSet.add(new String("catalog5"));

       Map map=cache.getAll(hashSet);
       Set results = cache.entrySet(filter);
        
           for (Iterator i = results.iterator(); i.hasNext();)
               {
               Map.Entry e = (Map.Entry) i.next();
               System.out.println("Catalog ID: "+e.getKey() + ", Title: "+e.getValue());
               }
        }
    
    public static void main(String[] args) 
       {
       DatabaseCache databaseCache = new DatabaseCache();
       databaseCache.createCache();
       databaseCache.addEntry();
       databaseCache.queryCache();
       }
}

Note the following features of the database cache class file:

  • A NamedCache object is created using the getCache method of the CacheFactory class in the createCache method.

    NamedCache cache = CacheFactory.getCache("DBBackedCache");
    
  • The DBBackedCache matches the cache pattern DBBacked* and is, therefore, mapped to a distributed caching scheme distributed-db-backed in the cache-config.xml file. Add a cache entry using the put() method of the NamedCache object.

    cache.put(new String("catalog3"), new String("Tuning Grid Management"));
    
  • Because the write-through mechanism is used, the new cache entry gets synchronized with the database; a new row is added to the CATALOG table. Comment out all the methods except the createCache and addEntry methods.

  • When the put method is invoked, the store method, which maps the new cache entry to the database table CATALOG using JDBC, gets invoked in the DBCacheStore class. The output from the Coherence application is displayed in the Log window and a new cache entry is added. The output shows that the operational configuration deployment descriptor is loaded, the cache configuration is loaded, a new cluster is created, and the DistributedCache service has joined the cluster.

  • The new cache entry can be removed with the remove method of the NamedCache object.

    cache.remove(new String("catalog3"));
    
  • Bulk uploading of cache entries is performed using the putAll method.

  • A cache entry is retrieved using the get method of the NamedCache object. For example, retrieving the cache entry for ID catalog1:

    System.out.println((String) cache.get("catalog1"));
    
  • When the get() method is invoked, the load method, which retrieves database table data using JDBC, gets invoked in the DBCacheStore class.

  • Bulk retrieval is performed using the getAll method of the NamedCache object.

  • Coherence supports searching for cache entries based on a search criteria using filters. Coherence filters are available in the com.tangosol.util.filter package. In Oracle Coherence Enterprise Edition and Grid Edition, indexes can be added to the Coherence cache to improve performance. You query the database cache using a LikeFilter filter, which matches cache entries with a specified pattern. To query a database cache, the cache entries must be created before querying, and the cache entries must be retrieved into the cache using the get() or getAll() method before a query using a filter can be performed. Therefore, you can retrieve database data and create a collection of cache entries using the getAll() method.

    HashSet hashSet=new HashSet(); 
    hashSet.add(new String("catalog1")); 
    hashSet.add(new String("catalog2")); 
    hashSet.add(new String("catalog3")); 
    Map map=cache.getAll(hashSet);
    
  • Create a LikeFilter filter to search for cache entries starting with Tuning.

    Filter filter = new LikeFilter(IdentityExtractor.INSTANCE, "Tuning%", '\\', true);
    
  • Query the database cache using the entrySet() method with the LikeFilter filter.

    Set results = cache.entrySet(filter);
    
  • Iterate over the results of the query. Display the key and value of the cache entries that are retrieved.

    for (Iterator i = results.iterator(); i.hasNext();) 
       {
       Map.Entry e = (Map.Entry) i.next();
       System.out.println("Catalog ID: "+e.getKey() + ", Title: "+e.getValue());
       }
    
  • Coherence supports continuous query using the com.tangosol.net.cache.ContinuousQueryCache class. A continuous query is a query that is kept up-to-date using a continuous query cache. In a ContinuousQueryCache, the results of a query are updated using event listeners on events that could change the results of the query. Create a ContinuousQueryCache object using the NamedCache object and the LikeFilter object.

    ContinuousQueryCache queryCache = new ContinuousQueryCache(cache, filter);
    
  • Create a result set by using the entrySet() method.

    Set results = queryCache.entrySet(filter);
    

9.3.5 Run the Database Cache Application

To run the Oracle Database cache application:

  1. Stop any running cache servers. See "Stopping Cache Servers" for more information.

  2. Start the cache server (JPAServer). Right click the project and select Run As then Run Configurations. In the Run Configurations dialog box, select JPACacheServer to display its configuration. Click Run.

  3. Create a run configuration for the DatabaseCache program.

    1. In the Run Configurations dialog box, click the New launch configuration icon.

    2. Enter DatabaseCacheClient in the Name field. Ensure that Interaction is in the Project field and com.oracle.handson.DatabaseCache is in the Main class field.

    3. In the Coherence tab, enter the path to the cache configuration file in the Cache configuration descriptor field: C:\home\oracle\workspace\Interaction\src\cache-config.xml. Select Local storage: Disabled (cache client). Enter a unique value, such as 3155, in the Cluster port field.

    4. Open the Classpath tab. The Classpath tab should look similar to Figure 9-4.

      Figure 9-4 Classpath for the DatabaseCache Program

      Classpath for the DatabaseCache Program
      Description of "Figure 9-4 Classpath for the DatabaseCache Program"

    5. Click Apply then Run.

      Example 9-9 illustrates the expected results.

      Example 9-9 Output of the DatabaseCache Program

      ...
      Group{Address=224.12.1.0, Port=3155, TTL=4}
       
      MasterMemberSet(
        ThisMember=Member(Id=2, Timestamp=2013-12-20 12:28:41.013, Address=10.159.165.75:8090, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:1976, Role=OracleHandsonDatabaseCache)
        OldestMember=Member(Id=1, Timestamp=2013-12-20 12:27:53.503, Address=10.159.165.75:8088, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:7320, Role=CoherenceServer)
        ActualMemberSet=MemberSet(Size=2
          Member(Id=1, Timestamp=2013-12-20 12:27:53.503, Address=10.159.165.75:8088, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:7320, Role=CoherenceServer)
          Member(Id=2, Timestamp=2013-12-20 12:28:41.013, Address=10.159.165.75:8090, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:1976, Role=OracleHandsonDatabaseCache)
          )
        MemberId|ServiceVersion|ServiceJoined|MemberState
          1|12.1.3|2013-12-20 12:27:53.503|JOINED,
          2|12.1.3|2013-12-20 12:28:41.013|JOINED
        RecycleMillis=1200000
        RecycleSet=MemberSet(Size=0
          )
        )
       
      TcpRing{Connections=[1]}
      IpMonitor{Addresses=0}
       
      2013-12-20 12:28:41.265/3.800 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
      2013-12-20 12:28:41.295/3.830 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/Oracle/coherence/lib/coherence.jar!/reports/report-group.xml"
      2013-12-20 12:28:41.715/4.250 Oracle Coherence GE 12.1.3.0.0 <Info> (thread=NameService:TcpAcceptor, member=2): TcpAcceptor now listening for connections on 10.159.165.75:8090.3
      2013-12-20 12:28:42.086/4.621 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=DistributedCache, member=2): Service DistributedCache joined the cluster with senior service member 1
      Catalog ID: catalog5, Title: Tuning Database
      Catalog ID: catalog4, Title: Tuning Coherence
      Catalog ID: catalog3, Title: Tuning Grid Management
      

      Example 9-10 illustrates the cache server response to the DatabaseCache program.

      Example 9-10 Cache Server Response to the DatabaseCache Program

      ...
      Started DefaultCacheServer...
      
      2013-12-20 12:28:41.208/50.536 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-12-20 12:28:41.013, Address=10.159.165.75:8090, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:1976, Role=OracleHandsonDatabaseCache) joined Cluster with senior member 1
      2013-12-20 12:28:41.275/50.603 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 joined Service Management with senior member 1
      2013-12-20 12:28:42.296/51.624 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=DistributedCache, member=1): Member 2 joined Service DistributedCache with senior member 1
      2013-12-20 12:28:42.377/51.705 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2013-12-20 12:28:41.013, Address=10.159.165.75:8090, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:1976, Role=OracleHandsonDatabaseCache) due to a peer departure; removing the member.
      2013-12-20 12:28:42.377/51.705 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-12-20 12:28:42.377, Address=10.159.165.75:8090, MachineId=47251, Location=site:,machine:TPFAEFFL-LAP,process:1976, Role=OracleHandsonDatabaseCache) left Cluster with senior member 1
      2013-12-20 12:28:42.378/51.706 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=DistributedCache, member=1): Member 2 left service DistributedCache with senior member 1
      2013-12-20 12:28:42.378/51.706 Oracle Coherence GE 12.1.3.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 left service Management with senior member 1
      

      If you receive any exceptions, such as the following:

      java.lang.IllegalArgumentException: No scheme for cache: "cachename, 
      

      You may be able to remove them by editing the cache-config.xml file and replacing DBBacked* in the <cache-name> element with *. Re-run the DatabaseCache application in Eclipse. You should not see any exceptions.

  4. Note that because you are using a write-through cache, the database table is also updated. From the SQL prompt, enter the following code:

    select * from hr.catalog;
    

    Example 9-11 illustrates the results.

    Example 9-11 Output from the SELECT Statement

    ...
    SQL> select * from hr.catalog;
     
    ID
    -------------------------
    VALUE
    --------------------------------------------------------------------------------
     
    catalog1
    Tuning Undo Tablespace
     
    catalog2
    Tuning Your View Objects
     
    catalog3
    Tuning Grid Management
     
     
    ID
    -------------------------
    VALUE
    --------------------------------------------------------------------------------
     
    catalog4
    Tuning Coherence
     
    catalog5
    Tuning Database
     
     
    SQL>