Database Change Notification and TopLink Cache Invalidation

How-To Document

January 2006

After reading this How-To document, you will be able to:

Software Requirements

Conventions

The following conventions are used in this document:

Introduction

This How-To document provides information on a TopLink stale data problem and a two-part solution to address the stale data problem.

TopLink Stale Data Problem

A common procedure among database applications is to cache data during application operation. Sometimes, this can result in some cached application data becoming stale as another application may change the data in the database, thus rendering the cached data obsolete. This could happen without the cached application knowing about it.

This How-To document provides an outline of the required setup procedures using the TopLink Employee example to illustrate.

Database Change Notification and Application Cache Invalidation Solution

A simple two-part solution can be used to minimize, and in some cases eliminate, occurrences of the stale data problem as follows:

Guidelines to which a proper database change notification solution should adhere include:


Note:

If notification messages are sent too frequently, the performance of the database and notified application(s) operation may be severely degraded.

Notification and TopLink Cache Invalidation Solution

This section provides information on database change notification and TopLink cache invalidation solution.

Database Change Notification

Oracle Database 10g and subsequent versions use triggers and Java Message Service (JMS) messaging implemented by Oracle Advanced Queuing (AQ) as follows:

TopLink Cache Invalidation

An application enabled by TopLink extracts the table name and the primary key value(s) from the JMS message and invalidates the corresponding object in the TopLink cache. Note that TopLink 10g Release 3 (10.1.3) or higher is required.

Database Setup

This section provides setup information for the Oracle database Users, Advanced Queue, and Triggers.

Users

The following procedure assumes that the dbuser user already exists and that the TopLink Employee example is set up and populated in its default schema.

  1. Connect as a DBA:

    CONNECT SYSTEM/MANAGER
    
    
  2. Enable the dbuser to enqueue (send) the messages into any queue:

    EXEC DBMS_AQADM.GRANT_SYSTEM_PRIVILEGE(privilege => ENQUEUE_ANY',grantee
        => 'dbuser',admin_option => FALSE);
    
    
  3. Allow the dbuser to call the enqueue method in PL/SQL:

    GRANT AQ_USER_ROLE, EXECUTE ON DBMS_AQ TO dbuser;
    
    
  4. Create the app user:

    CREATE USER app IDENTIFIED BY password DEFAULT TABLESPACE users TEMPORARY
        TABLESPACE temp;
    
    
  5. Grant the app user access to all database objects in dbuser schema:

    GRANT SELECT, INSERT, UPDATE, DELETE ON dbuser.address to app;
    ...
    
    
  6. Enable the app user to dequeue (receive) the messages from any queue:

    EXEC DBMS_AQADM.GRANT_SYSTEM_PRIVILEGE(privilege => 'DEQUEUE_ANY',
        grantee => 'app', admin_option => FALSE);
    
    
  7. Allow the app user to dequeue JMS messages in a Java application:

    GRANT AQ_USER_ROLE, EXECUTE ON DBMS_AQIN, EXECUTE ON DBMS_AQJMS TO app;
    
    
  8. Create aqadm - the user to own the queue:

    CREATE USER aqadm IDENTIFIED BY password DEFAULT TABLESPACE users
        TEMPORARY TABLESPACE temp;
    GRANT CONNECT,RESOURCE,AQ_ADMINISTRATOR_ROLE TO aqadm;
    
    

Advanced Queue

The notify_queue allows for multiple consumers (applications that receive messages) and sends Oracle's implementations of JMS messages.

  1. Connect as a queue owner:

    CONNECT aqadm/aqadm
    
    
  2. Create and start the queue:

    EXEC DBMS_AQADM.CREATE_QUEUE_TABLE (queue_table => 'notify_queue_table',
        multiple_consumers => TRUE, queue payload_type => 'SYQ.AQ$_JMS_TEXT_
        MESSAGE');
    EXEC DBMS_AQADM.CREATE_QUEUE (queue_name => 'notify_queue',queue_table =>
        'notify_queue_table');
    EXEC DBMS_AQADM.START_QUEUE (queue_name => 'notify_queue');
    
    

Alternatively, if there is only a single application to be notified, the queue table may be created with multiple_consumers=>FALSE.

Triggers

A trigger is created for each table that will send one or more notification messages. You can create two helper functions first to simplify the trigger code.

  1. Connect as a TopLink user of the schema where the TopLink Employee example is set up:

    CONNECT dbuser/dbuser
    
    
  2. Create the notify_make_msg function provided. This function creates the message and populates it with the application ID (app1, app2, ... found in USER) and the table name:

    CREATE OR REPLACE FUNCTION notify_make_msg (table_name VARCHAR2) RETURN
        SYS.AQ$_JMS_TEXT_MESSAGE AS msg SYS.AQ$_JMS_TEXT_MESSAGE;
    BEGIN
        msg := SYS.AQ$_JMS_TEXT_MESSAGE.CONSTRUCT();
        msg.set_string_property('APP', USER);
        RETURN msg;
    END;
    
    
  3. Create the notify_enqueue procedure provided. This procedure sends the message to notify_queue. TopLink throws an exception, but the message may be ignored if there are no recipients to receive it:

    CREATE OR REPLACE PROCEDURE notify_enqueue  (msg SYS.AQ$_JMS_TEXT_
        MESSAGE) AS queue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
        msg_properties  DBMS_AQ.MESSAGE_PROPERTIES_T;
        msg_id          RAW(16);
        no_recipients_for_message EXCEPTION;
        PRAGMA EXCEPTION_INIT(no_recipients_for_message, -24033);
    BEGIN
        DBMS_AQ.ENQUEUE(queue_name => 'notify_enqueue', enqueue_options =>
        queue_options, message_properties => msg_properties, payload => msg,
        msgid => msg_id);
    EXCEPTION
        WHEN no_recipients_for_message THEN NULL;-- ignore
    END;
    
    
  4. Create a trigger for the employee table:

    CREATE OR REPLACE TRIGGER notify_employee AFTER UPDATE OR DELETE ON
        employee FOR EACH ROW DECLARE msg SYS.AQ$_JMS_TEXT_MESSAGE;
    BEGIN
        --a single call per trigger, pass the table name
        msg := NOTIFY_MAKE_MSG('EMPLOYEE');
        --a call for every primary key field
        msg.set_double_property('EMP_ID', :old.EMP_ID);
        NOTIFY_ENQUEUE(msg);
    END;
    
    

    If there is only a single application that requires notification, the trigger need not enqueue the message in the event that it was caused by the application:

    IF USER = 'app' THEN
        RETURN;
    END IF;
    
    

After the transaction is committed, the corresponding JMS message is delivered to all database subscribers.

Application Setup

This section provides information on how to connect the application enabled by TopLink and information on JMS and TopLink cache invalidation.

Connecting the Application

The application enabled by TopLink must be amended to connect using the app user. However, it will work with database objects in the dbuser schema by setting the user to dbuser via either the preLogin() event handler in Example: preLogin event handler or the postLogin() event handler in Example: postLogin event handler.

preLogin event handler

//The pre-login method
public void preLogin(SessionEvent event){
   event.getSession().getLogin().setTableQualifier("dbuser");
}

postLogin event handler

//The post-login method
public void postLogin(SessionEvent event){
    event.getSession().executeNonSelectingCall(new SQLCall("ALTER SESSION SET CURRENT_SCHEMA = dbuser"));
}

JMS

An application obtains ConnectionFactory and Destination by invoking a Java Naming and Directory Interface (JNDI) lookup. The code example in Example: How to obtain ConnectionFactory and Destination using the oracle.jms package illustrates how ConnectionFactory and Destination may be obtained with the use of the oracle.jms package.

Note: the condition defined in the selector string filters out messages generated by the app user.

How to obtain ConnectionFactory and Destination using the oracle.jms package

import javax.jms.*;
import oracle.jms.*;

String url = "jdbc:oracle:thin:@localhost:1521:orcl"
String user = "app";
String password = "app";
String selector = "(APP IS NULL) OR (APP <> " + "'" + user + "')";

// multiple_consumers => TRUE case:
TopicConnectionFactory factory =  AQjmsFactory.getTopicConnectionFactory(url,null);
TopicConnection conn = factory.createTopicConnection(user, password);
TopicSession topicSession = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = ((AQjmsSession) topicSession).getTopic("aqadm", "notify_queue");
Subscriber subscriber = topicSession.createSubscriber(topic, selector, false);
….

// multiple_consumers => FALSE case:
QueueConnectionFactory factory = AQjmsFactory.getQueueConnectionFactory(url,null);
QueueConnection conn = factory.createQueueConnection(user, password);
QueueSession queueSession = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = ((AQjmsSession) queueSession).getQueue("aqadm", "notify_queue");
QueueReceiver receiver= queueSession.createReceiver(queue, selector);
….

TopLink Cache Invalidation

To process change notification messages, an application enabled with TopLink must prepare two maps: the first maps a table name to a class, the second maps table names to a vector of primary key fields' names.

When a notification message is received, the application:

A sample CacheInvalidator Java class file that does all of the above may be downloaded here.

References

Oracle TopLink Cache Invalidation How-To document

Oracle9i SQL Reference. Release 2 (9.2)

Oracle9i PL/SQL User's Guide and Reference. Release 2 (9.2)

Oracle9i Application Developer's Guide - Advanced Queuing. Release 2 (9.2)

Oracle9i Supplied PL/SQL Packages and Types Reference. Release 2 (9.2)

Oracle9i Supplied Java Packages Reference Release 2 (9.2)

Sun Java JMS Docs Web site


Oracle TopLink, 10g Release 3 (10.1.3)

The Programs (which include both the software and documentation) contain proprietary information; they are provided under a license agreement containing restrictions on use and disclosure and are also protected by copyright, patent, and other intellectual and industrial property laws. Reverse engineering, disassembly, or decompilation of the Programs, except to the extent required to obtain interoperability with other independently created software or as specified by law, is prohibited.

The information contained in this document is subject to change without notice. If you find any problems in the documentation, please report them to us in writing. This document is not warranted to be error-free. Except as may be expressly permitted in your license agreement for these Programs, no part of these Programs may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose.

If the Programs are delivered to the United States Government or anyone licensing or using the Programs on behalf of the United States Government, the following notice is applicable:

U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the Programs, including documentation and technical data, shall be subject to the licensing restrictions set forth in the applicable Oracle license agreement, and, to the extent applicable, the additional rights set forth in FAR 52.227-19, Commercial Computer Software—Restricted Rights (June 1987). Oracle Corporation, 500 Oracle Parkway, Redwood City, CA 94065

The Programs are not intended for use in any nuclear, aviation, mass transit, medical, or other inherently dangerous applications. It shall be the licensee's responsibility to take all appropriate fail-safe, backup, redundancy and other measures to ensure the safe use of such applications if the Programs are used for such purposes, and we disclaim liability for any damages caused by such use of the Programs.

Oracle, JD Edwards and PeopleSoft are registered trademarks of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

The Programs may provide links to Web sites and access to content, products, and services from third parties. Oracle is not responsible for the availability of, or any content provided on, third-party Web sites. You bear all risks associated with the use of such content. If you choose to purchase any products or services from a third party, the relationship is directly between you and the third party. Oracle is not responsible for: (a) the quality of third-party products or services; or (b) fulfilling any of the terms of the agreement with the third party, including delivery of products or services and warranty obligations related to purchased products or services. Oracle is not responsible for any loss or damage of any sort that you may incur from dealing with any third party.

Alpha and Beta Draft documentation are considered to be in prerelease status. This documentation is intended for demonstration and preliminary use only. We expect that you may encounter some errors, ranging from typographical errors to data inaccuracies. This documentation is subject to change without notice, and it may not be specific to the hardware on which you are using the software. Please be advised that prerelease documentation in not warranted in any manner, for any purpose, and we will not be responsible for any loss, costs, or damages incurred due to the use of this documentation.