jdbc與oracle資料庫改變通知(Database Change Notification)

來源:互聯網
上載者:User

Database Change Notification的作用就是當資料庫中的被監聽table變化時(包括資料和表結構的更改),自動嚮應用程式發出一個通知。這對讀多寫少應用的緩衝更新,以及避免輪詢資料庫很有用。

需要3個步驟:
1. 註冊。

2. 用一個查詢表示監聽哪個(些)表的修改通知。

3. 響應。

在11g中,可以對查詢結果集監聽,而不是對所有記錄的改變觸發通知事件。

下面的代碼在java1.6,ojdbc6.jar驅動, oracle10g r2環境下通過運行。

<%@ page language="java" contentType="text/html;charset=GBK" isELIgnored="false"%>
<%@ page import="javax.naming.InitialContext, java.util.*, java.math.BigDecimal, javax.sql.DataSource, java.sql.*, oracle.sql.*, oracle.jdbc.*, oracle.jdbc.dcn.*" %>

<%!
    Connection getConnection(){
        try{
        InitialContext ctx = new InitialContext();
        DataSource ds = (DataSource)ctx.lookup("auditDatasource");
        ctx.close();
        Connection conn=ds.getConnection();
        return conn;
        }catch(Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }
%>

<% String type=request.getParameter("type"); %>

<%
 if("register".equals(type)){
    Connection conn = getConnection();
    OracleConnection oconn = (OracleConnection)conn.unwrap(OracleConnection.class);
    DatabaseChangeRegistration dcr = (DatabaseChangeRegistration)application.getAttribute("DatabaseChangeRegistration");
    if(dcr!=null){  //撤銷以前的註冊
        try{
          oconn.unregisterDatabaseChangeNotification(dcr);
        }catch(java.sql.SQLException e){}  //避免ORA-29970: 指定的註冊 ID 不存在
        application.removeAttribute("DatabaseChangeRegistration");
        System.out.println("unregisterDatabaseChangeNotification, regId="+dcr.getRegId());
        dcr=null;
    }
    Properties prop = new Properties();

//ROWIDs may be rolled-up if the total shared memory consumption due to ROWIDs is too large (exceeds 1% of the dynamic shared pool size), OR if too many rows were modified
    prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS,"true");     //要取得更改記錄的rowid
    prop.setProperty(OracleConnection.DCN_IGNORE_DELETEOP,"true");    //忽略delete
    //default: prop.setProperty(OracleConnection.NTF_LOCAL_TCP_PORT, 47632);    //這裡可設定程式的tcp監聽連接埠,預設是47632

//Specifies the time in seconds after which the registration will be automatically expunged by the database. If 0 or NULL, then the registration persists until the client explicitly unregisters it.
    prop.setProperty(OracleConnection.NTF_TIMEOUT, "3600");   //設定逾時,這裡是1個小時,屆時資料庫和磁碟機的資源將自動釋放。如果為0或不設定,則永不到期,直到程式停止監聽,當資料庫發送更新通知時,因沒有監聽連接埠,資料庫隨後釋放資源。

   //prop.setProperty(OracleConnection.NTF_QOS_PURGE_ON_NTFN, "true");    //在第一次通知後,註冊就作廢撤銷

    dcr = oconn.registerDatabaseChangeNotification(prop);    //註冊
    System.out.println("registerDatabaseChangeNotification, regId="+dcr.getRegId());   //列印註冊ID,在oracle裡 select * from dba_CHANGE_NOTIFICATION_REGS 可以看到記錄。
    application.setAttribute("DatabaseChangeRegistration", dcr);
try
{
    dcr.addListener(new DatabaseChangeListener(){     //增加事件監聽
        public void onDatabaseChangeNotification(DatabaseChangeEvent e){
            DatabaseChangeEvent.EventType etype = e.getEventType();
            System.out.println("receive "+ etype+" event, RegId="+ e.getRegId());
            if(etype != DatabaseChangeEvent.EventType.OBJCHANGE) return;     //如果不是資料改變事件,如表結構更改或刪表,則返回。
            TableChangeDescription[] tcds = e.getTableChangeDescription();
            
            for( TableChangeDescription tcd : tcds){
                System.out.println("changed table="+ tcd.getTableName());
                java.util.EnumSet<TableChangeDescription.TableOperation> tops =    tcd.getTableOperations();  //獲得表操作類型
                for( TableChangeDescription.TableOperation top: tops)
                    System.out.println("... TableOperation="+ top);
                RowChangeDescription[] rcds =    tcd.getRowChangeDescription();
                for(RowChangeDescription rcd: rcds){  //獲得更改的記錄描述,包括更改類型insert, update, delete,以及rowid.

                    System.out.println("... RowOperation=" + rcd.getRowOperation()+", rowid="+rcd.getRowid().stringValue());
                }
            }
        }
    }
    );
    Statement stmt = oconn.createStatement();
    ((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);
    ResultSet rs = stmt.executeQuery("select 1 from RPT_CHENJUN_DDJH_ERR_CODE where 1=2");  //這裡表示關聯RPT_CHENJUN_DDJH_ERR_CODE表的變更事件。
    //while (rs.next())    {}
    for(String tableName: dcr.getTables())
        System.out.println("DatabaseChangeRegistration ON "+tableName);
    rs.close();
    stmt.close();
}
catch(SQLException ex)
{
    if(oconn != null)
    oconn.unregisterDatabaseChangeNotification(dcr);
    throw ex;
}
finally
{
try
    {conn.close();}catch(Exception innerex){ innerex.printStackTrace(); }
}

}
%>

<% if("unregister".equals(type)){
            int regId = Integer.parseInt( request.getParameter("regId"));
            System.out.println("unregister regId="+regId);
            Connection conn = getConnection();
            try{
                OracleConnection oconn = (OracleConnection)conn.unwrap(OracleConnection.class);
                //oconn.unregisterDatabaseChangeNotification(regId);  //不支援的特性
                //NPE, bug!
                DatabaseChangeRegistration dcr = oconn.getDatabaseChangeRegistration(regId);
                oconn.unregisterDatabaseChangeNotification(dcr); //The registration will be destroyed in the server and in the driver
            }finally{
                try{conn.close();}catch(Exception innerex){ innerex.printStackTrace(); }
            }
    }
%>

<%
  if("insert".equals(type)){
  Connection conn =null;
    try{
        conn = getConnection();
        OracleConnection oconn = (OracleConnection)conn.unwrap(OracleConnection.class);
        oconn.setAutoCommit(false);
        Statement stmt2 = oconn.createStatement();
        stmt2.executeUpdate("insert into RPT_CHENJUN_DDJH_ERR_CODE values (-21, '',null)", Statement.RETURN_GENERATED_KEYS);
        ResultSet autoGeneratedKey = stmt2.getGeneratedKeys();
        if(autoGeneratedKey.next())
        System.out.println("inserted one row with    ROWID="+autoGeneratedKey.getString(1));
        stmt2.close();
        oconn.commit();
        oconn.close();
    }
    catch(SQLException ex) { ex.printStackTrace(); }
    finally{
            if(conn!=null)  conn.close();
    }
}

%>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.