Java - Oracle Database Change Notification

Adrian picture Adrian · Nov 18, 2014 · Viewed 7.3k times · Source

I am trying to implement a event listener which can identify DATABASE CHANGE NOTIFICATION (Oracle). According to the reference website, it said that event will triggle and print ROW_ID when something change in EXAMPLE table. I want this project running, and it should give me a message "give me something!" if I manually insert/update data in Database. However, it is my understanding that this code will terminate no matter what since there is no infinite loop that can be interrupted by the event. Please correct me if I am wrong.

Additional Question]
By setting OracleConnection.DCN_NOTIFY_ROWIDS as true, it will notify every event including inserting, updating, deleting. Am I correct? I was confused with the meaning of "Database change events will include row-level details, such as operation type and ROWID"

my code:

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.jdbc.OracleStatement;
import oracle.jdbc.dcn.DatabaseChangeEvent;
import oracle.jdbc.dcn.DatabaseChangeListener;
import oracle.jdbc.dcn.DatabaseChangeRegistration;

public class DBTest {
    static final String USERNAME = "username";
    static final String PASSWORD = "password";
    static String URL = "jdbc:oracle:thin:@url:port/name";

    public static void main(String[] args) {
        DBTest oracleDCN = new DBTest();
        try {
            oracleDCN.run();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void run() throws Exception {
        OracleConnection conn = connect();
        Properties prop = new Properties();
        prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
        DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotification(prop);

        try {
            dcr.addListener(new DatabaseChangeListener() {
                public void onDatabaseChangeNotification(DatabaseChangeEvent dce) {
                    System.out.println("GIVE ME SOMETHING!");
                }
            });
            //conn.unregisterDatabaseChangeNotification(dcr);
            Statement stmt = conn.createStatement();
            ((OracleStatement) stmt).setDatabaseChangeRegistration(dcr);
            ResultSet rs = stmt.executeQuery("select * from Schema.T_TEST");
            while (rs.next()) {
            }
            rs.close();
            stmt.close();
        } catch (SQLException ex) {
            if (conn != null) {
                conn.unregisterDatabaseChangeNotification(dcr);
                conn.close();
            }
            throw ex;
        }
    }

    OracleConnection connect() throws SQLException {
        OracleDriver dr = new OracleDriver();
        Properties prop = new Properties();
        prop.setProperty("user", DBTest.USERNAME);
        prop.setProperty("password", DBTest.PASSWORD);
        return (OracleConnection) dr.connect(DBTest.URL, prop);
    }
}

More details can be found in the reference website

Answer

Jean de Lavarene picture Jean de Lavarene · Jul 12, 2017

As you guessed you need keep your main thread alive otherwise your program will exit. You can just make it sleep or do something more useful. Also you can close the JDBC connection but you don't want to close (unregister) the registration immediately. The way Database Change Notification works is with an internal listening thread that runs within the driver. This listening thread will receive outband events sent by the server through a dedicated network socket, process these events and notify the listeners. This listening thread will be closed if you unregister. When you're no longer interested in receiving these events you can create another connection to the database to unregister which will end up closing the driver's listening thread.