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

PHP 利用 Oracle 資料庫變更通知 (DCN) 實作快取自動失效

     編輯:PHP 綜合知識

背景動機

傳統快取依賴 TTL (時間到期) 或手動清除,無法即時反映資料庫變更。Oracle Database Change Notification (DCN) 允許應用程式註冊查詢,資料表異動並 Commit 時自動推送通知,PHP 收到通知即可精準失效對應快取。

架構流程

[Oracle DB] --(DCN 通知)--> [PHP Listener Daemon] --> [Memcached/Redis] 失效快取
     │                                                           ▲
     └------------<-- 應用查詢 (快取未命中時回查) ---------------┘

資料庫端設定

-- 授權
GRANT CHANGE NOTIFICATION TO app_user;
GRANT EXECUTE ON DBMS_CHANGE_NOTIFICATION TO app_user;

-- 確保 Job Queue 執行程序啟用
ALTER SYSTEM SET job_queue_processes = 4 SCOPE=BOTH;

-- 建立通知記錄表 (選用)
CREATE TABLE dcn_log (
    log_id NUMBER GENERATED ALWAYS AS IDENTITY,
    op_date TIMESTAMP DEFAULT SYSTIMESTAMP,
    table_name VARCHAR2(60),
    msg VARCHAR2(200)
);

PL/SQL 通知處理程序 (伺服端推送 HTTP 回調)

CREATE OR REPLACE PROCEDURE send_dcn_callback(
    p_url   IN VARCHAR2,
    p_table IN VARCHAR2,
    p_rowid IN VARCHAR2
) IS
    l_req   UTL_HTTP.REQ;
    l_resp  UTL_HTTP.RESP;
    l_err   VARCHAR2(200);
BEGIN
    l_req := UTL_HTTP.BEGIN_REQUEST(p_url || '?table=' || p_table || '&rowid=' || p_rowid);
    UTL_HTTP.SET_HEADER(l_req, 'User-Agent', 'Oracle-DCN');
    l_resp := UTL_HTTP.GET_RESPONSE(l_req);
    INSERT INTO dcn_log (table_name, msg) VALUES (p_table, l_resp.reason_phrase);
    UTL_HTTP.END_RESPONSE(l_resp);
EXCEPTION
    WHEN OTHERS THEN
        l_err := SUBSTR(SQLERRM, 1, 200);
        INSERT INTO dcn_log (table_name, msg) VALUES (p_table, l_err);
END;
/

-- 註冊查詢 (範例:監聽 ORDERS 表)
DECLARE
    l_reg_id NUMBER;
BEGIN
    DBMS_CHANGE_NOTIFICATION.ENABLE_REG(
        reg_id      => l_reg_id,
        query_text  => 'SELECT * FROM orders',
        callback    => 'send_dcn_callback',
        callback_ctxt => 'https://php-app.example.com/dcn_callback.php',
        qosflags    => DBMS_CHANGE_NOTIFICATION.QOS_ROWIDS + DBMS_CHANGE_NOTIFICATION.QOS_QUERY
    );
    DBMS_OUTPUT.PUT_LINE('Registered: ' || l_reg_id);
END;
/

PHP 回調端點 (dcn_callback.php)

addServer('127.0.0.1', 11211);

// 依資料表對應快取鍵前綴
$prefix_map = [
    'ORDERS' => 'order:',
    'ORDER_ITEMS' => 'order_item:',
    'CUSTOMERS' => 'customer:',
];
$prefix = $prefix_map[$table] ?? $table . ':';

// 失效相關快取 (簡單策略:刪除前綴所有鍵需掃描,生產建議維護反向索引或用 Tag)
$keys_to_delete = [];
// 這裡需配合應用層快取鍵命名規範,例如 order:123, order:list:user:456
// 簡易示範:刪除單筆與常見列表
$mem->delete($prefix . $rowid);
$mem->delete($prefix . 'list:all');
$mem->delete($prefix . 'list:recent');

http_response_code(200);
echo 'OK';

PHP 長期監聽程式 (替代 HTTP 回調)

OCI8 擴充支援 oci_register_taf_callback、oci_set_notify_callback (需 Oracle Instant Client),可在 PHP CLI Daemon 中直接接收通知,避免 HTTP 開銷與防火牆問題。架構更簡潔,但需自行管理進程存活。

注意事項與限制

  • DCN 通知為異步、最佳努力送達,極端情況可能遺失 (DB 重啟、網路中斷)
  • 大量異動時通知風暴,建議批次合併或節流處理
  • 需 Oracle Enterprise Edition + 高可用選項授權
  • PHP 端需穩定部署、監控、自動重啟 (systemd/Supervisor)
  • 快取鍵設計需支援精準失效 (Tag、版本號、反向索引)

替代方案

  • CDC (Change Data Capture) + Kafka:資料庫層面捕獲 Binlog/Redo Log,推送至訊息佇列,多消費者處理
  • 觸發器寫入通知表 + 輪詢:相容性高、延遲秒級、實作簡單
  • 應用層雙寫:寫 DB 同時失效快取,需分散式事務或補償機制保證一致性
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved