1

I am using Java 8 and using oracle version as the Oracle Database 12c Enterprise Edition Release 12.1.0.2.0.

We are using below driver to connect to the database.

 <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.11.0.0</version>
    </dependency>

I have gone through the some of the articles related to implement the Database Change Notification and implemented the below code.

DBTest

public class DBTest {
    private static final String USERNAME="username";
    private static final String PASSWORD="password";
    private static final String URL="jdbc:oracle:thin:@<hostname>:port:servicename";
    
    public static void main(String[] args) throws SQLException {
        DBTest dbTest=new DBTest();
        dbTest.testDBChangeNotification();
    }

    private void testDBChangeNotification() throws SQLException {

        System.out.println("Invoke the testDBChangeNotification Started .....");
        Properties prop = new Properties();
        prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
        OracleConnection conn = connect();
        DatabaseChangeRegistration dcr = null;
        try {
            dcr = conn.registerDatabaseChangeNotification(prop);
            DCNListener dcnListener = new DCNListener();
            dcr.addListener(dcnListener);

            Statement stmt = conn.createStatement();
            ((OracleStatement) stmt).setDatabaseChangeRegistration(dcr);
            ResultSet rs = stmt.executeQuery("select * from Example");
            while (rs.next()) {
            }
            rs.close();
            stmt.close();

            String[] tableNames = dcr.getTables();
            Arrays.stream(tableNames)
                    .forEach(i ->System.out.println("Table " + i+ " registered." ));
        }
        catch(SQLException sqlException){
            if (conn != null)
            {
                conn.unregisterDatabaseChangeNotification(dcr);
                conn.close();
            }
            sqlException.printStackTrace();
            throw sqlException;
        }

        System.out.println("Finished the testDBChangeNotification Started .....");
    }
    OracleConnection connect() throws SQLException {
        OracleDriver dr = new OracleDriver();
        Properties prop = new Properties();
        prop.setProperty("user", DBTest.USERNAME);
        prop.setProperty("password", DBTest.PASSWORD);
        OracleConnection oracleConn =  (OracleConnection) dr.connect(DBTest.URL, prop);
        if(oracleConn!=null){
            System.out.println("oracle connection is available");
        }
        return oracleConn;
    }
}

DBListener

 public class DCNListener implements DatabaseChangeListener {

    @Override
    public void onDatabaseChangeNotification(DatabaseChangeEvent databaseChangeEvent) {
        System.out.println("Received the database change event notification");
        TableChangeDescription[] tableChanges = databaseChangeEvent.getTableChangeDescription();

        for (TableChangeDescription tableChange : tableChanges) {

            RowChangeDescription[] rcds = tableChange.getRowChangeDescription();

            for (RowChangeDescription rcd : rcds) {

                RowChangeDescription.RowOperation op = rcd.getRowOperation();
                String rowId = rcd.getRowid().stringValue();
                System.out.println("Value of the rowId:" + rowId);

                switch (op) {

                    case INSERT:
                        System.out.println("Insert the value of RowId: " + rowId);
                        break;

                    case UPDATE:
                        System.out.println("Update the value of RowId: " + rowId);
                        break;

                }

            }

        }
        System.out.println("Finished the database change event notification");
    }
}

Issue with the above code is I can see the registration is successful, but I am still not able to receive the database change notification in my DCNListener when I am inserting and updating in the table from oracle SQL Developer and commiting the insert/update.

I just want to know what I am doing wrong in above code due to which I am not able to receive notifications when DataChanges

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Beast
  • 639
  • 2
  • 14
  • 29
  • 1
    Your code works for me. I created an `EXAMPLE` table in my 18c XE database, ran your code, and then inserted and updated some data in this table. Change notifications were picked up by your code. – Luke Woodward Mar 26 '22 at 13:35
  • @Thanks Luke Woodward for quick reply. I am trying to run this code in my employer's laptop. There possibly be a firewall that might have been blocking the database to send the notification to listener running on my machine. So does it require the change in my code or some changes via network side ( such as opening of Port or something). can you guide me ? – Beast Mar 27 '22 at 03:12
  • Not sure what could cause the code to not work for you. It's not a permissions thing, you'd get a different error if your user account didn't have permission to create change notification registrations. As you surmise, it's possible that a firewall is blocking the connection. If you want to take a look at the port number being used, query the view `USER_CHANGE_NOTIFICATION_REGS`. In particular, look at the contents of the `CALLBACK` column. – Luke Woodward Mar 27 '22 at 11:52
  • @Luke I have given the grant change notification to devadmin user. The table data I am updating is in the different schema .Example. I can see the 47632 as port in callback column of view USER_CHANGE_NOTIFICATION_REGS which seems to be default port for JDBC driver for listening. Is there a way I can check whether that port is open or not in my system to receive the notification? Is there a way to confirm in oracle database tables that if the notification is send by oracle to decrease the scope of the problem? – Beast Mar 27 '22 at 13:42
  • Schema differences shouldn't matter: I was able to connect as one user and receive notifications for changes to a table in another schema. To test whether there's a firewall blocking the issue you will need to connect to the database server and check whether you can connect from the DB server to your laptop. How you do this depends on which OS the DB server runs. – Luke Woodward Mar 27 '22 at 18:20
  • 1
    You can try to set the option OracleConnection.DCN_CLIENT_INIT_CONNECTION to "true" in registerDatabaseChangeNotification. This will make the client initiate the connection that's used for event notifications instead of the server. Also be sure that the program DBTest doesn't exit. – Jean de Lavarene Mar 28 '22 at 11:56
  • I was also facing the same issue, same code was not working for me. But when I set the following property (as per comment from Jean de Lavarene, it started working. prop.setProperty(OracleConnection.DCN_CLIENT_INIT_CONNECTION, "true"); – Rajib Biswas Dec 07 '22 at 10:15

0 Answers0