Sample CacheStore

Sample CacheStore

This page provides a simple implementation of the com.tangosol.net.cache.CacheStore interface. Cache stores are used by caches to read and write cache entries to external stores such as a database. This example uses JDBC to perform these tasks. See the cache configuration samples, for an example of a database cache configuration.

package com.tangosol.examples.coherence;


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;


/**
* An example implementation of CacheStore
* interface.
*
* @author erm 2003.05.01
*/
public class DBCacheStore
        extends Base
        implements CacheStore
    {
    // ----- constructors ---------------------------------------------------
    /**
    * Constructs DBCacheStore for a given database table.
    *
    * @param sTableName the db table name
    */
    public DBCacheStore(String sTableName)
        {
        m_sTableName = sTableName;
        configureConnection();
        }

	/** 
	* Set up the DB connection.
	*/
	protected void configureConnection()
		{
		try
			{
			Class.forName("org.gjt.mm.mysql.Driver");
			m_con = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD);
			m_con.setAutoCommit(true);
			}
		catch (Exception e)
			{
			throw ensureRuntimeException(e, "Connection failed");
			}
		}


	// ---- accessors -------------------------------------------------------

    /** 
    * Obtain the name of the table this CacheStore is persisting to.
    * 
    * @return the name of the table this CacheStore is persisting to
    */
    public String getTableName()
        {
        return m_sTableName;
        }

    /** 
    * Obtain the connection being used to connect to the database.
    * 
    * @return the connection used to connect to the database
    */
    public Connection getConnection()
        {
        return m_con;
        }


    // ----- CacheStore Interface --------------------------------------------

    /**
    * Return the value associated with the specified key, or null if the
    * key does not have an associated value in the underlying store.
    *
    * @param oKey  key whose associated value is to be returned
    *
    * @return the value associated with the specified key, or
    *         <tt>null</tt> if no value is available for that key
    */
    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;
        }

    /**
    * Store the specified value under the specific key in the underlying
    * store. This method is intended to support both key/value creation
    * and value update for a specific key.
    *
    * @param oKey    key to store the value under
    * @param oValue  value to be stored
    *
    * @throws UnsupportedOperationException  if this implementation or the
    *         underlying store is read-only
    */
    public void store(Object oKey, Object oValue)
        {
        Connection con     = getConnection();
        String     sTable  = getTableName();
	String     sSQL;
        
        // the following is very inefficient; it is recommended to use DB
        // specific functionality i.e. REPLACE for MySQL or MERGE for Oracle
	if (load(oKey) != null)
		{
		// key exists - update
		sSQL = "UPDATE " + sTable + " SET value = ? where id = ?";
		}
	else
		{
		// new key - insert
		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);
		}
        }

    /**
    * Remove the specified key from the underlying store if present.
    *
    * @param oKey key whose mapping is to be removed from the map
    *
    * @throws UnsupportedOperationException  if this implementation or the
    *         underlying store is read-only
    */
    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);
            }
        }

	/**
	* Remove the specified keys from the underlying store if present.
	*
	* @param colKeys  keys whose mappings are being removed from the cache
	*
	* @throws UnsupportedOperationException  if this implementation or the
	*         underlying store is read-only
	*/
	public void eraseAll(Collection colKeys)
		{
		throw new UnsupportedOperationException();
		}

	/**
	* Return the values associated with each the specified keys in the
	* passed collection. If a key does not have an associated value in
	* the underlying store, then the return map will not have an entry
	* for that key.
	*
	* @param colKeys  a collection of keys to load
	*
	* @return a Map of keys to associated values for the specified keys
	*/
	public Map loadAll(Collection colKeys)
		{
		throw new UnsupportedOperationException();
		}

	/**
	* Store the specified values under the specified keys in the underlying
	* store. This method is intended to support both key/value creation
	* and value update for the specified keys.
	*
	* @param mapEntries   a Map of any number of keys and values to store
	*
	* @throws UnsupportedOperationException  if this implementation or the
	*         underlying store is read-only
	*/
	public void storeAll(Map mapEntries)
		{
		throw new UnsupportedOperationException();
		}

    /**
    * Iterate all keys in the underlying store.
    *
    * @return a read-only iterator of the keys in the underlying store
    */
    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();
        }

    
    // ----- data members ---------------------------------------------------

    /**
    * The connection.
    */
    protected Connection m_con;

    /**
    * The db table name.
    */
    protected String m_sTableName;

	/**
	* Driver class name.
	*/
	private static final String DB_DRIVER   = "org.gjt.mm.mysql.Driver";

	/**
	* Connection URL.
	*/
	private static final String DB_URL      = "jdbc:mysql://localhost:3306/CacheStore";

	/**
	* User name.
	*/
	private static final String DB_USERNAME = "root";

	/**
	* Password.
	*/
	private static final String DB_PASSWORD = null;
    }