简体   繁体   中英

Oracle Data Change Notification Timeout and Workflow

Good time!

We have the Oracle DCN feature configured in our java application. Everything works fine, but there are some troubles on the application's shutdown. If the application is down unexpectedly (for example a tomcat process is killed via the kill -9 command), DCN subscribers are left hanged in a DB ( select * from user_change_notification_regs; ). Also, I can see that every subscriber has a 4294967295-second timeout.

So could somebody, please, suggest:

1. how to set the timeout for a subscriber;
2. why subscribers are left hanged even after all JDBC connections are down. Well, if there is no correspondence between a JDBC connection and a DCN subscription, how oracle would send DCN to a java application when the last one would eventually be up (are there any ping operations from Oracle to an application, or it is something like a durable subscription in JMS)?

UPDATE : I've found an answer for the first point. There is the OracleConnection.NTF_TIMEOUT parameter that could be set for a DatabaseChangeRegistration :

Properties properties = new Properties();
properties.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
properties.setProperty(OracleConnection.DCN_BEST_EFFORT, "true");
properties.setProperty(OracleConnection.NTF_TIMEOUT, "3600");

DatabaseChangeRegistration databaseChangeRegistration = oracleConnection.registerDatabaseChangeNotification(properties);

The records you have persisted in user_change_notification_regs table has to be deleted explicitly since DBMS does not keep track of that 'The JDBC connection which prepared this connection is still alive' which requires a heart beat mechanism. Therefore when your server restarts, you have to explicitly delete(unregister) those records. Here is an example.

try (Connection conn = ConnManager.getConnection();) {
         if (conn.isWrapperFor(OracleConnection.class)) {

                try (OracleConnection oracleConnection = conn.unwrap(OracleConnection.class);
                        Statement stmt = oracleConnection.createStatement()) {
                    ResultSet rs = stmt.executeQuery("select regid,callback from USER_CHANGE_NOTIFICATION_REGS");

                    while (rs.next()) {
                        long regid = rs.getLong(1);
                        String callback = rs.getString(2);
                        ((OracleConnection) stmt.getConnection()).unregisterDatabaseChangeNotification(regid, callback);
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(TableBase.class.getName()).log(Level.SEVERE, null, ex);
        } 

You can simply put this code in a static block of a class or a initializing method which will be executed only once. If you set a timeout for the listener, oracle server side driver enables the heart beat mechanism for your connection which could slightly decrease application performance.

Oracle will eventually clean up the dead registrations. You can also enable keep alive in the sqlnet parameter file on the server-side to speed up this cleaning process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM