Oracle Advanced Queuing (AQ) 提供企業級消息隊列,支持 JMS 1.1 標準。結合 Java 存儲過程,可在數據庫內直接實現生產者/消費者模式,無需外部 Broker。本文給出生產環境可用的完整代碼:隊列創建、Java 類、Call Spec、調用驗證。
-- 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');
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) {}
}
}
}
session.commit() 同時提交消息與業務數據,保證原子性。AQjmsFactory.getQueueConnectionFactory(defaultConnection()) 零配置複用會話連接。SYS.AQ$_JMS_TEXT_MESSAGE 對應 JMS TextMessage,還有 BytesMessage/MapMessage/ObjectMessage 等類型。-- 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!'
利用 AQ 實現「數據變更 → 發送失效消息 → Web 節點接收刷新緩存」:
jms_send_receive('INVALIDATE:TABLE_NAME:PK_VALUE')。JCache.invalidate(key) 或直接清除本地緩存 Map。優勢:數據庫原生、無外部依賴、事務一致性、支持 RAC 多實例廣播。
Oracle AQ + Java 存儲過程 + JMS 標準,構建了零中間件、事務一致、標準化的異步消息能力。核心代碼約 50 行,部署僅需 loadjava 與一條 CREATE PROCEDURE。適合「數據變更觸發異步動作」「跨會話通知」「緩存失效廣播」等場景,是 Oracle 開發者手中被低估的利器。