`
pn2008
  • 浏览: 7218 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

Using Database Change Notification (DCN) with a Coherence Cache

阅读更多
http://itnewscast.com/database/using-database-change-notification-dcn-coherence-cache
Using Database Change Notification (DCN) with a Coherence CacheThanks to The Blas from Pas for this storyFeb 01, 2010 7:27pm Database I needed to ensure my coherence cache which was storing a table from a database was kept in sync. To do that I used Database Change Notification (DCN) in the 11g JDBC driver with a 11.2 RDBMS. Few things I needed to ensure were as follows.


1. Firstly I made sure my DCN listener on the client which determines what refresh to perform on the cache does this using the Executor interface to call a runnable task in it's own thread. That is done to make sure if the operation takes time it's done in it's own thread and won't hold up the listener itself.

package support.au.coherence.dcn.server.db;import java.util.concurrent.Executor;import oracle.jdbc.dcn.DatabaseChangeEvent;import oracle.jdbc.dcn.DatabaseChangeListener;import oracle.jdbc.dcn.RowChangeDescription;import oracle.jdbc.dcn.RowChangeDescription.RowOperation;import oracle.jdbc.dcn.TableChangeDescription;public class DCNListener implements DatabaseChangeListener{DeptDCNRegister demo;DCNListener(DeptDCNRegister dem){  demo = dem;}public void onDatabaseChangeNotification(DatabaseChangeEvent databaseChangeEvent){  System.out.println("DCNListener: got an event (" + this + ")");  System.out.println(databaseChangeEvent.toString());  TableChangeDescription [] tableChanges =    databaseChangeEvent.getTableChangeDescription();  for (TableChangeDescription tableChange : tableChanges)  {    RowChangeDescription[] rcds = tableChange.getRowChangeDescription();    for (RowChangeDescription rcd : rcds)    {      System.out.println("Affected row -> " +                         rcd.getRowid().stringValue());      RowOperation ro = rcd.getRowOperation();          Executor executor = new DBExecutor();      String rowid = rcd.getRowid().stringValue();          if (ro.equals(RowOperation.INSERT))      {              System.out.println("INSERT occurred");        executor.execute(new HandleDBRefresh(rowid, "insert"));      }      else if (ro.equals(RowOperation.UPDATE))      {        System.out.println("UPDATE occurred");        executor.execute(new HandleDBRefresh(rowid, "update"));      }      else if (ro.equals(RowOperation.DELETE))      {        System.out.println("DELETE occurred");        executor.execute(new HandleDBRefresh(rowid, "delete"));      }      else      {        System.out.println("Only handling INSERT/DELETE/UPDATE");      }    }  }  synchronized( demo )  {    demo.notify();  }}}2. The "DBExecutor" is defined as follows.

package support.au.coherence.dcn.server.db;import java.util.concurrent.Executor;public class DBExecutor implements Executor{public void execute(Runnable command){  new Thread(command).run();}}3. The runnable class "HandleDBRefresh" is defined as follows.

package support.au.coherence.dcn.server.db;import com.tangosol.net.CacheFactory;import com.tangosol.net.CacheFactoryBuilder;import com.tangosol.net.NamedCache;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import support.au.coherence.dcn.server.CacheHelper;import support.au.coherence.dcn.server.Dept;public class HandleDBRefresh implements Runnable{private DBConnectionManager connMgr = null;private String rowId;private String action;public HandleDBRefresh(){}public HandleDBRefresh(String rowId, String action){  super();  this.rowId = rowId;  this.action = action;}public void run(){  PreparedStatement stmt = null;  ResultSet rset = null;  Connection conn = null;  try  {    connMgr = DBConnectionManager.getInstance();    if (!action.toLowerCase().equals("delete"))    {      conn = connMgr.getConnection();      stmt = conn.prepareStatement        ("select rowid, deptno, dname from dept where rowid = ?");      stmt.setString(1, rowId);      rset = stmt.executeQuery();      rset.next();    }      CacheHelper cacheHelper = CacheHelper.getInstance();      // check if action    if (action.toLowerCase().equals("delete"))    {      cacheHelper.removeEntry(rowId);      System.out.println("Cache record delete");    }    else if (action.toLowerCase().equals("insert"))    {      // add to cache      if (rset != null)      {        Dept d = new Dept(rset.getInt(2), rset.getString(3));        cacheHelper.updateEntry(rset.getString(1), d);        System.out.println("Cache updated with new record");      }    }    else if (action.toLowerCase().equals("update"))    {      // refresh record in cache      if (rset != null)      {        Dept d = new Dept(rset.getInt(2), rset.getString(3));        cacheHelper.updateEntry(rset.getString(1), d);        System.out.println("Cache record updated");      }    }  }  catch (Exception e)  {    throw new RuntimeException      ("Error updating cache: rowid [" + rowId + "] " + e);  }  finally  {    if (rset != null)    {      try      {        rset.close();      }      catch (SQLException se)      {      }    }    if (stmt != null)    {      try      {        stmt.close();      }      catch (SQLException se)      {      }    }    if (conn != null)    {      try      {        connMgr.returnConnection(conn);      }      catch (SQLException se)      {      }    }    }}public void setRowId(String rowId){  this.rowId = rowId;}public String getRowId(){  return rowId;}public void setAction(String action){  this.action = action;}public String getAction(){  return action;}}4. "DeptDCNRegister" is defined as follows.

  package support.au.coherence.dcn.server;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.HashMap;import java.util.Map;import java.util.Properties;import oracle.jdbc.OracleConnection;import oracle.jdbc.OracleStatement;import oracle.jdbc.dcn.DatabaseChangeRegistration;@SuppressWarnings("unchecked")public class DeptDCNRegister{  private DBConnectionManager connMgr = null;  //private final String depSQL = "select * from dept";  private DatabaseChangeRegistration dcr = null;  private static DeptDCNRegister instance = null;    static  {    try    {      instance = new DeptDCNRegister();    }    catch (Exception e)    {      throw new RuntimeException("Error creating instance of DeptDCNRegister", e);    }  }    private DeptDCNRegister () throws SQLException  {     connMgr = DBConnectionManager.getInstance();    OracleConnection conn = (OracleConnection) connMgr.getConnection();    if (dcr == null)    {      registerDCN(conn);    }  }    public static DeptDCNRegister getInstance()  {    return instance;  }      private void registerDCN (OracleConnection conn) throws SQLException  {    /*     * register a listener for change notofication to be displayed to standard out     * for testing purposes     */      Properties props = new Properties();    props.put(OracleConnection.DCN_NOTIFY_ROWIDS, "true");    props.put(OracleConnection.NTF_QOS_RELIABLE, "false");    props.setProperty(OracleConnection.DCN_BEST_EFFORT, "true");        dcr = conn.registerDatabaseChangeNotification(props);        // Add the dummy DCNListener which is DCNListener.java class    DCNListener list = new DCNListener(this);    dcr.addListener(list);    Statement stmt = conn.createStatement();    // Associate the statement with the registration.    ((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);    ResultSet rs = stmt.executeQuery("select * from dept where 1 = 2");    while (rs.next())    {      // do nothing no , need to just need query to register the DEPT table    }    String[] tableNames = dcr.getTables();    for(int i=0; i < tableNames.length; i++)    {      System.out.println(tableNames[i]+" successfully registered.");    }        // close resources    stmt.close();    rs.close();  }    public void closeDCN (OracleConnection conn) throws SQLException  {    conn.unregisterDatabaseChangeNotification(dcr);    conn.close();  }}5. Finally the key for Dept cache records is the ROWID at the database table level to ensure it's always unique not to mention that's what drives the specific operation so makes it easier this way. The ROWID is what is provided to the listener for the table changes so makes sense to use that as the KEY within the coherence cache.

I did give some thought into making the DCN listener run within the DB but loading the required JARS turned me off that idea. Wasn't sure how I could connect to a coherence cluster itself as storage disabled from within the DB itself to be honest. Otherwise this would of been a good option as the registration would of been active as long as the DB was running.


http://feeds.feedburner.com/TheBlasFromPas
Read the entire article at its source
分享到:
评论

相关推荐

    oracle data change notification,支持10.2以上的Oracle版本,速度很快,效率高

    Oracle Data Change Notification(DCN)是Oracle数据库提供的一项高级特性,自Oracle 10g Release 2(10.2版本)开始引入。这个功能允许应用程序高效地跟踪和响应数据库中的数据变化,而无需频繁地执行查询来检查...

    Registered State Change Notification

    Registered State Change Notification

    开源项目-adililhan-Zabbix-Desktop-Notification-with-Golang.zip

    开源项目“adililhan-Zabbix-Desktop-Notification-with-Golang”是一个利用Golang语言实现的Zabbix桌面通知系统。这个项目旨在为Zabbix监控系统提供一个轻量级且高效的本地通知解决方案,使得用户能够在自己的桌面...

    Page change monitor with a sound notification-crx插件

    "Page change monitor with a sound notification-crx插件"是一款针对网页内容变化监控的浏览器扩展程序,主要面向英语用户。这款插件特别适用于Microsoft Teams或其他协作团队环境,它能有效地帮助用户跟踪并提醒...

    Application Development with Swift 无水印pdf 0分

    Develop a series of applications with Swift using the development kits and new/updated APIs Use the new features of iOS 8 to add new flavor to your applications A hands-on guide with detailed code ...

    Notification

    在Android开发中,`Notification`是用户界面的一个关键组件,用于在状态栏向用户显示重要的信息或提醒。在"疯狂Android中有关Notification的简单例子"这个主题中,我们将深入探讨`Notification`的基本概念、创建过程...

    Creating Notification Box Using jQuery.zip

    本项目“Creating Notification Box Using jQuery”旨在教你如何利用jQuery库来创建一个通知框,这在现代网页设计中是非常常见的功能,例如显示系统消息、用户反馈或提示信息。 jQuery是一个轻量级、高性能的...

    Notification最新用法、实现Notification的通知栏常驻、Notification的big View、解决Notification点击无效

    在Android开发中,Notification是应用与用户交互的重要方式,它能够在状态栏显示消息,即使用户不在应用程序中也能接收到信息。本教程将深入探讨Notification的最新用法,如何实现通知栏常驻,以及如何利用big View...

    Notification示例

    本示例着重讲解了如何创建和使用不同类型的Notification,包括普通Notification、折叠式Notification以及悬挂式Notification,并涉及到Notification的显示等级设置。 1. **普通Notification**: 这是最基础的...

    Notification的示例源码

    在Android开发中,`Notification`是用户界面的一个关键组件,用于在状态栏中显示消息,即使应用程序在后台运行,也能提醒用户有新的活动或事件发生。`Notification`的设计旨在提供一致且非侵入性的用户体验,使得...

    ios5 Notification示例

    在iOS开发中,Notification是一种非常重要的通信机制,它允许应用程序的不同组件之间相互通信,而无需直接耦合。本文将详细讲解iOS中的Notification机制,以及如何在iOS 5中使用Notification进行参数传递。 首先,...

    android notification完全解析Demo

    在Android开发中,Notification是应用与用户交互的重要方式,它能够在状态栏中显示信息,即使用户不在应用程序中也能提醒用户有新的活动或消息。本文将深入解析Android Notification的工作原理、设计模式以及如何...

    Laravel开发-lumen-notification

    -&gt;line('Thank you for using our application!'); } public function toArray($notifiable) { return [ // ... ]; } } ``` 然后,你需要定义接收通知的模型,并实现`Notifiable`接口。Lumen中,你可以在`...

    实现Notification的通知栏常驻

    在Android系统中,Notification是应用与用户交互的重要方式之一,特别是在后台运行时,它能向用户提供关键信息。常驻Notification是指即使用户关闭了应用程序,Notification仍然保留在通知栏,持续提醒用户有未处理...

    Ext JS Notification 插件

    在Ext JS中,“Notification”插件是用于显示通知消息的一个组件,它可以帮助开发者在用户界面上创建吸引人且易于理解的提示信息。本文将深入探讨Ext JS Notification插件的使用方法、功能特性以及如何集成到项目中...

    Notification顶部通知栏demo

    在Android开发中,`Notification`是系统提供的一种机制,它能够在状态栏或者顶部通知栏显示信息,即使应用在后台运行或者被用户关闭,仍然能够向用户传达关键信息。本示例"Notification顶部通知栏demo"显然是为了...

    Dialogs and Notification Logs using Jquery.zip

    本项目"Dialogs and Notification Logs using Jquery.zip"显然关注的是如何利用jQuery来创建对话框(Dialogs)和通知日志(Notification Logs),这在用户交互中是非常常见且重要的功能。下面我们将深入探讨这两个...

Global site tag (gtag.js) - Google Analytics