7 Interacting with the Cache and the Database

In this chapter, you create and configure an Oracle Coherence cache in Oracle JDeveloper using all the concepts presented in this tutorial. This chapter has the following sections:

7.1 Introduction

A Coherence cache is a collection of data objects that serves as an intermediary between the database and the client applications. Database data may 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 may 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 Oracle 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 may be performed on the data objects.

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

Oracle Coherence supports different types of caches.

  • Replicated caches—In a replicated cache, data is replicated to each of the application server nodes in the cluster. This is suitable if faster read access is required but not suitable for writes, because data has to be written to each of the nodes. The drawback of replicated caches is that they require a large memory footprint as every node has a copy of every object.

  • Distributed (or "partitioned") caches—In a distributed cache, 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.

Oracle 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.

The 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. Some of the commonly used cache types are described in Table 7-1.

Table 7-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


7.2 Creating a Cache Application

This exercise consolidates all of the concepts presented in this tutorial. In this exercise you will:

  • Create a Java class that creates a NamedCache and can put and get cache entries.

  • Create a cache configuration file to define the mapping for cache names, cache types, and naming patterns.

  • Create a Java class that creates a connection to the Oracle database and can retrieve and store table data.

  • Create a database cache. This class will add cache entries, query the database cache, and retrieve entries.

To create and configure a Coherence cache:

  1. Create a project and an application in Oracle JDeveloper.

    1. Create a project called Interact in Oracle JDeveloper. See "Creating a New Project in an Existing Application" if you need detailed information.

    2. Create a Java class, CoherenceCache, in the project. See "Creating a Java Class" if you need detailed information.

      The Java class will be used to create a Coherence cache.

    3. Create an XML document, cache-config.xml, as the cache configuration deployment descriptor.

      To add the XML document, right-click the project and choose New. In the New Gallery window, select XML under General categories. Select XML Document and click OK. Change the File Name to cache-config.xml. Note: You will update the contents of cache-config.xml in Step 4 of this exercise.

  2. Add the Coherence JAR file coherence.jar to the project libraries. Also add the Oracle JDBC library, which is required for database access to the project libraries.

    The Coherence JAR file is in the oracle\product\coherence\lib directory (the Oracle Coherence installation). It should already be present in the Libraries and Classpath dialog box. To add the Oracle JDBC library, click Tools > Project Properties > Add Library > Oracle JDBC.

    Figure 7-1 Adding the Oracle JDBC Libraries to the Classpath

    Adding the Oracle JDBC Libraries to the Classpath
  3. Modify the Run configuration for the application to add the cache configuration file as a run-time Java option.

    1. Select the project node and select Tools > Project Properties. In the Project Properties window, select Run/Debug/Profile. The Default configuration is selected by default. Click Edit for the Default configuration.

    2. In the Edit Run Configuration window, select Launch Settings. In the Java Options field, specify the cache configuration file (cache-config.xml) with -Dtangosol.coherence.cacheconfig=[path-to-cache-config-file]/cache-config.xml.

      For example, for the Oracle Coherence application that you created, specify the following (your path to cache-config.xml may vary) in the Java Options field and click OK.

      -Dtangosol.coherence.cacheconfig=/home/oracle/labs/cache-config.xml
      

      Figure 7-2 Setting the Cache Configuration File for Runtime Options

      Setting the Cache Configuration File for Runtime Options

      Click OK in the Run/Debug/Profile window. The cache configuration file will be added as a run-time Java option to the Coherence Java application.

  4. In the cache configuration file:

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

    • Specify the default mapping to cache type default-replicated and map cache name VirtualCache to cache type default-distributed.

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

    The cache configuration file is listed in Example 7-1. Copy the contents of this example to the cache-config.xml file in Oracle JDeveloper.

    Example 7-1 Cache Configuration File

    <?xml version="1.0"?>
    <!DOCTYPE cache-config SYSTEM "cache-config.dtd">
    <cache-config>
        <caching-scheme-mapping>
            
            <cache-mapping>
                <cache-name>VirtualCache</cache-name>
                <scheme-name>default-distributed</scheme-name>
            </cache-mapping>
        </caching-scheme-mapping>
        <caching-schemes>
            <!--
            Default Distributed caching scheme.
            -->
            <distributed-scheme>
                <scheme-name>default-distributed</scheme-name>
                <service-name>DistributedCache</service-name>
                <backing-map-scheme>
                    <class-scheme>
                        <scheme-ref>default-backing-map</scheme-ref>
                    </class-scheme>
                </backing-map-scheme>
            </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>
    
  5. Create the cache application.

    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. An instance of a cache is created from the CacheFactory class. Create a NamedCache using the getCache() method of the CacheFactory class. 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 that holds resources that are shared across nodes in a cluster. Add a cache entry using the put() method.

      cache.put (key, "Hello Cache");
      
    4. A cache entry can be retrieved using the get() method.

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

      Example 7-2 illustrates a possible solution. You can copy the code to the CoherenceCache application in Oracle JDeveloper.

      Example 7-2 Implementation of a Coherence Cache

      package com.oracle.coherence.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();
              }
      }
      
    5. Stop any running cache servers. Start the JPA cache server (jpa-cache-server.cmd) that you created in Chapter 6, "Using JPA with Coherence".

    6. Right-click the Oracle Coherence application CoherenceCache.java and click Run.

      The Oracle Coherence application runs and the output is displayed in the Log window. The output shows that the operational configuration is loaded from tangosol-coherence.xml, the cache configuration is loaded from cache-config.xml, a new cluster is created, and the DistributedCache service joins the cluster. The operational deployment descriptor tangosol-coherence.xml specifies the operational and run-time settings used by Coherence for its clustering, communication, and data management services.

      Example 7-3 Output of the Coherence Cache Application

      2009-04-21 14:32:59.272/0.703 Oracle Coherence 3.5/453b (Pre-release) <Info> (thread=main, member=n/a): Loaded operational configuration from resource "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/tangosol-coherence.xml"
      2009-04-21 14:32:59.272/0.703 Oracle Coherence 3.5/453b (Pre-release) <Info> (thread=main, member=n/a): Loaded operational overrides from resource "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
      2009-04-21 14:32:59.272/0.703 Oracle Coherence 3.5/453b (Pre-release) <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
      2009-04-21 14:32:59.288/0.719 Oracle Coherence 3.5/453b (Pre-release) <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified
      
      Oracle Coherence Version 3.5/453b (Pre-release)
       Grid Edition: Development mode
      Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
      
      2009-04-21 14:32:59.600/1.031 Oracle Coherence GE 3.5/453b (Pre-release) <Info> (thread=main, member=n/a): Loaded cache configuration from file "C:\home\oracle\exercises\cache-config.xml"
      2009-04-21 14:33:00.928/2.359 Oracle Coherence GE 3.5/453b (Pre-release) <D5> (thread=Cluster, member=n/a): Service Cluster joined the cluster with senior service member n/a
      2009-04-21 14:33:01.131/2.562 Oracle Coherence GE 3.5/453b (Pre-release) <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2009-04-21 14:33:00.944, Address=130.35.99.50:8089, MachineId=49714, Location=site:us.oracle.com,machine:tpfaeffl-pc,process:5124, Role=OracleCoherenceCoherenceCache, Edition=Grid Edition, Mode=Development, CpuCount=1, SocketCount=1) joined cluster "cluster:0x2EDB" with senior Member(Id=1, Timestamp=2009-04-21 14:31:32.585, Address=130.35.99.50:8088, MachineId=49714, Location=site:us.oracle.com,machine:tpfaeffl-pc,process:5148, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=1, SocketCount=1)
      2009-04-21 14:33:01.194/2.625 Oracle Coherence GE 3.5/453b (Pre-release) <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
      2009-04-21 14:33:01.194/2.625 Oracle Coherence GE 3.5/453b (Pre-release) <D5> (thread=Cluster, member=n/a): Member 1 joined Service JpaDistributedCache with senior member 1
      2009-04-21 14:33:01.350/2.781 Oracle Coherence GE 3.5/453b (Pre-release) <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
      2009-04-21 14:33:01.835/3.266 Oracle Coherence GE 3.5/453b (Pre-release) <D5> (thread=DistributedCache, member=2): Service DistributedCache joined the cluster with senior service member 2
      Hello Cache
      2009-04-21 14:33:01.975/3.406 Oracle Coherence GE 3.5/453b (Pre-release) <D4> (thread=ShutdownHook, member=2): ShutdownHook: stopping cluster node
      Process exited with exit code 0.
      

7.3 Creating a Database Cache

In this section, you create a cache backed by the Oracle database. This is also referred to as an "Oracle database cache".

  1. Create an Oracle database cache.

    1. Invoke SQL*Plus.

      Navigate to Start > All Programs > Oracle Database 10g Express Edition > Run SQL Command Line.

    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 the file as dbscript.sql in the /home/oracle/labs/ folder.

      Example 7-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 7-5 illustrates the output from the script.

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

      SQL*Plus: Release 10.2.0.1.0 - Production on Thu Apr 21 14:45:53 2009
      Copyright (c) 1982, 2005, Oracle.  All rights reserved.
      SQL> connect hr/hr;
      Connected.
      SQL> @/home/oracle/labs/dbscript.sql
      
      Table created
      
      1 row created
      
      1 row created
      
  2. Create a custom CacheStore.

    1. Create a Java class DBCacheStore in Oracle JDeveloper. See "Creating a Java Class" if you need detailed information.

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

      Example 7-6 illustrates a possible solution. Copy the code to the DBCacheStore application in Oracle JDeveloper. The DBCacheStore application uses Java Database Connectivity (JDBC) to access Oracle Database, but another mechanism, such as Hibernate or Java Data Objects (JDO), may also be used.

      Example 7-6 Database CacheStore Implementation

      package com.oracle.coherence.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:XE";
                  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();
              }
          
          }
      
    3. Modify the cache configuration file that you created earlier (cache-config.xml) for the database cache.

      To connect a cache to a back-end database, a cache configuration file (cache-config.xml) element cachestore-scheme is required. The cachestore-scheme element must be configured with a custom class that implements either the com.tangosol.net.cache.CacheLoader or com.tangosol.net.cache.CacheStore interface.

      Copy the cache configuration file for the database cache in Example 7-7 and Replace the existing code in the cache-config.xml file in Oracle JDeveloper.

    Example 7-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.coherence.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>
       <listener/>
       <autostart>true</autostart>
      </distributed-scheme>
     </caching-schemes>
    </cache-config>
    
    

    In the cache configuration file, you have taken care of the following:

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

    —Specify the CacheStore scheme in the distributed scheme using the class coherence.DBCacheStore, which implements the CacheStore interface.

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

    —Coherence supports read/write caching of a data source for which the read-write-backing-map scheme is used. The read-write-backing-map scheme defines a backing map, which provides a size-limited cache of a persistent store. Here, you use the Write-Through mechanism. Oracle Coherence supports the types of read/write caching described in Table 7-2:

    Table 7-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 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.


  3. Create a Java class DatabaseCache for the database cache in Oracle JDeveloper.

    The class must contain a main method. See "Creating a Java Class" if you need detailed information.

    In the class file, add 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(). You can copy the code that is listed in Example 7-8.

    Example 7-8 Implementation for the Database Cache Class File

    package com.oracle.coherence.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");
            //cache.put(new String("catalog3"), new String("Evolving Grid Management"));
               // System.out.println((String) cache.get( "catalog3"));
            
        }
    
        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"));
            //System.out.println((String) cache.get( "catalog3"));
       
        }
    
        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);
            //ContinuousQueryCache queryCache = new ContinuousQueryCache(cache, filter);
            //Set results = queryCache.entrySet(filter);
            Set results = cache.entrySet(filter);
           /* Set results = cache.entrySet(filter);*/
            
            
    
           // if(results.isEmpty())
           // System.out.println("Result Set Empty");
                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.retrieveEntry();
            //databaseCache.eraseEntry();
           databaseCache.queryCache();
        }
    }
    

    Note the following features of the code:

    • A NamedCache object is created using the getCache() method of the CacheFactory class in the addEntry() 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 also 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 Oracle 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 may 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.

    • Oracle 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 may 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 may 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);
      
    • A LikeFilter filter is created to search for cache entries starting with Tuning.

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

      Set results = cache.entrySet(filter);
      
    • Iterate over the results of the query to output the cache entries 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());
      }
      
    • Oracle 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 );
      
    • A result set is created using the entrySet() method.

      Set results = queryCache.entrySet(filter);
      
  4. Stop any running cache servers. Start the JPA cache server (jpa-cache-server.cmd) that you created in Chapter 6, "Using JPA with Coherence".

  5. Right-click the DatabaseCache application in Oracle JDeveloper and select Run. Figure 7-3 illustrates the expected results.

    Figure 7-3 Results from Running the DatabaseCache Application

    Results from Running the DatabaseCache Application

    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 *. Save the file. Re-run the DatabaseCache application in Oracle JDeveloper. You should not see any exceptions now.

  6. Note that because you are using a Write-Through cache, the database table also gets updated. From the SQL prompt, enter the following code:

    select * from hr.catalog;
    

    Example 7-9 illustrates the results.

    Example 7-9 Output from the select Command

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