首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle AQ + JMS 異步消息實戰:Java 存儲過程發布/訂閱完整代碼示例

     編輯:Oracle 資料庫基礎

前言:數據庫原生消息隊列

Oracle Advanced Queuing (AQ) 提供企業級消息隊列,支持 JMS 1.1 標準。結合 Java 存儲過程,可在數據庫內直接實現生產者/消費者模式,無需外部 Broker。本文給出生產環境可用的完整代碼:隊列創建、Java 類、Call Spec、調用驗證。

一、 AQ 基礎設施腳本 (SQL*Plus 執行)

-- 1. 創建隊列表 (負載類型: JMS Text Message)
EXECUTE DBMS_AQADM.CREATE_QUEUE_TABLE(
  QUEUE_TABLE        => 'JMS_QUEUE_TABLE',
  QUEUE_PAYLOAD_TYPE => 'SYS.AQ$_JMS_TEXT_MESSAGE',
  COMMENT            => 'JMS Text Message Queue',
  MULTIPLE_CONSUMERS => FALSE,  -- 點對點模式
  COMPATIBLE         => '8.1.0'
);

-- 2. 創建隊列
EXECUTE DBMS_AQADM.CREATE_QUEUE(
  QUEUE_NAME  => 'JMS_TEXT_QUEUE',
  QUEUE_TABLE => 'JMS_QUEUE_TABLE'
);

-- 3. 啟動隊列 (啟用入隊/出隊)
EXECUTE DBMS_AQADM.START_QUEUE(QUEUE_NAME => 'JMS_TEXT_QUEUE');

-- 4. 權限授予 (應用用戶需 ENQUEUE/DEQUEUE 權限)
EXECUTE DBMS_AQADM.GRANT_QUEUE_PRIVILEGE('ENQUEUE', 'JMS_TEXT_QUEUE', 'APP_USER');
EXECUTE DBMS_AQADM.GRANT_QUEUE_PRIVILEGE('DEQUEUE', 'JMS_TEXT_QUEUE', 'APP_USER');

二、 Java 存儲過程核心代碼

import javax.jms.*;
import oracle.jms.*;
import java.sql.Connection;
import oracle.jdbc.OracleDriver;

public class JmsQueueDemo {
    // 發送並接收演示 (同步請求-響應模式)
    public static void runTest(String msgBody) {
        Connection dbConn = null;
        QueueConnection jmsConn = null;
        QueueSession session = null;
        QueueSender sender = null;
        QueueReceiver receiver = null;
        try {
            // 1. 獲取數據庫默認連接
            dbConn = new OracleDriver().defaultConnection();
            
            // 2. 創建 JMS 連接 (複用數據庫連接)
            QueueConnectionFactory qcf = AQjmsFactory.getQueueConnectionFactory(dbConn);
            jmsConn = qcf.createQueueConnection();
            session = jmsConn.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); // 事務由數據庫控制
            
            // 3. 獲取隊列對象
            Queue queue = ((AQjmsSession)session).getQueue("APP_USER", "JMS_TEXT_QUEUE");
            
            // 4. 創建生產者/消費者
            sender = session.createSender(queue);
            receiver = session.createReceiver(queue);
            
            // 5. 啟動連接 (開始接收消息)
            jmsConn.start();
            
            // 6. 發送消息
            TextMessage sMsg = session.createTextMessage(msgBody);
            sender.send(sMsg);
            session.commit(); // 提交數據庫事務 = 消息可見
            
            // 7. 同步接收 (演示用,生產通常異步 MDB)
            TextMessage rMsg = (TextMessage) receiver.receive(5000); // 5秒超時
            session.commit();
            
            // 8. 輸出結果
            String body = rMsg.getText();
            System.out.println("Message received: '" + body + "'");
            
        } catch (JMSException | SQLException e) {
            System.err.println("JMS Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 9. 資源關閉 (順序重要)
            try { if (receiver != null) receiver.close(); } catch (Exception ignore) {}
            try { if (sender != null) sender.close(); } catch (Exception ignore) {}
            try { if (session != null) session.close(); } catch (Exception ignore) {}
            try { if (jmsConn != null) jmsConn.close(); } catch (Exception ignore) {}
        }
    }
}

關鍵技術點

  • 事務統一:JMS Session 事務 = 數據庫事務,session.commit() 同時提交消息與業務數據,保證原子性。
  • 連接復用:AQjmsFactory.getQueueConnectionFactory(defaultConnection()) 零配置複用會話連接。
  • Payload 類型:SYS.AQ$_JMS_TEXT_MESSAGE 對應 JMS TextMessage,還有 BytesMessage/MapMessage/ObjectMessage 等類型。

三、 發布 Call Spec 並調用

-- 1. 加載 Java 類
loadjava -u app_user/pwd@orcl -v -resolve JmsQueueDemo.java

-- 2. 發布存儲過程
CREATE OR REPLACE PROCEDURE jms_send_receive(p_msg IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'JmsQueueDemo.runTest(java.lang.String)';
/

-- 3. 測試調用
SET SERVEROUTPUT ON SIZE 2000
CALL DBMS_JAVA.SET_OUTPUT(2000);

EXEC jms_send_receive('Hello Oracle AQ JMS!');
-- 輸出: Message received: 'Hello Oracle AQ JMS!'

四、 Web 緩存失效應用場景 (JCache/JSR-107 整合)

利用 AQ 實現「數據變更 → 發送失效消息 → Web 節點接收刷新緩存」:

  1. 業務表創建 AFTER INSERT/UPDATE/DELETE ROW TRIGGER,調用 jms_send_receive('INVALIDATE:TABLE_NAME:PK_VALUE')。
  2. Web 應用部署 Message Driven Bean (MDB) 或獨立消費者線程,監聽隊列。
  3. 收到消息 → 解析表名/主鍵 → 調用 JCache.invalidate(key) 或直接清除本地緩存 Map。
  4. 下次查詢強制回源數據庫,保證緩存一致性。

優勢:數據庫原生、無外部依賴、事務一致性、支持 RAC 多實例廣播。

五、 參考資源

六、 總結

Oracle AQ + Java 存儲過程 + JMS 標準,構建了零中間件、事務一致、標準化的異步消息能力。核心代碼約 50 行,部署僅需 loadjava 與一條 CREATE PROCEDURE。適合「數據變更觸發異步動作」「跨會話通知」「緩存失效廣播」等場景,是 Oracle 開發者手中被低估的利器。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved