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

WebLogic 9.2 JDBC Store 儲存 Session 發生 ORA-00001 唯一鍵衝突根因分析

     編輯:Java 相關知識

錯誤現象

<Error> <HTTP Session> <BEA-100087> 
The jdbc session data for session id: ... has been modified by another server in the cluster.
java.sql.SQLException: ORA-00001: unique constraint (SYSTEM.SYS_C003007) violated

叢集環境下,Session 持久化至資料庫表 wl_servlet_sessions,主鍵為 (wl_id, wl_context_path)。衝突表示嘗試插入重複的 wl_id。

表結構

CREATE TABLE wl_servlet_sessions (
    wl_id             VARCHAR2(100) NOT NULL,
    wl_context_path   VARCHAR2(100) NOT NULL,
    wl_is_new         CHAR(1),
    wl_create_time    NUMBER(20),
    wl_is_valid       CHAR(1),
    wl_session_values LONG RAW,
    wl_access_time    NUMBER(20),
    wl_max_inactive_interval INTEGER,
    PRIMARY KEY (wl_id, wl_context_path)
);

根因一:WebLogic 內部 Bug (CR331498)

觸發場景

  1. Request 1 進入,Session 建立並寫入 DB(dbLAT=1, triggerLAT=0)。
  2. Request 2 僅讀 Session,交給 LastAccessTimeTrigger 批次更新 triggerLAT(尚未寫入 DB,triggerLAT=2 在記憶體)。
  3. Cache 滿,Session 被擠出 Cache。
  4. Request 3 進入,Cache 未命中,從 DB 讀取舊資料(dbLAT=1, triggerLAT=0),重建 Session 物件 B。
  5. Trigger 觸發,將 triggerLAT=2 寫入 DB(wl_access_time=2)。
  6. Request 3 結束,呼叫 syncSession(),檢查 DB 記錄的 wl_access_time (2) 不等於記憶體 dbLAT (1) 或 triggerLAT (0),判定記錄不存在 → 呼叫 dbCreate() 插入 → ORA-00001。

本質

Cache 淘汰與 Trigger 批次更新的競態條件:Trigger 持有的 Session 參考未被視為 GC Root,導致 Session 被 Cache 移除後仍在 Trigger 佇列中,造成同一 Session ID 存在兩個記憶體實例。

修正

  • 升級 WebLogic 修補補丁(CR331498 修正版)。
  • 或調大 session-descriptor > cache-size(預設 1024)減少淘汰機率。

根因二:負載平衡器 Session Stickiness 失效

前端代理(Apache mod_wl, F5, Nginx 等)未正確維持 Session 親和性,導致同一 Session ID 的請求分散到叢集不同節點:

  • Node A 建立 Session 並寫入 DB。
  • Node B 接收同一 Session ID 請求,從 DB 讀取。
  • 兩節點並發修改 Session,後寫入者發現 DB 版本不符 → 嘗試 dbCreate() → 唯一鍵衝突。

排查

  • 開啟 WebLogic DebugWLProxy 或 Apache mod_jk 日誌,確認是否發生 Failover。
  • 檢查 Cookie JSESSIONID 路徑、Domain 設定是否正確。
  • 硬體 LB 需啟用 Source IP Affinity 或 Cookie Insert 模式。

通用建議

  • 資料庫層面:將 wl_servlet_sessions 主鍵改為單獨 wl_id(若應用允許),或增加 server_id 列區分節點(需自訂 JDBC Store)。
  • 監控:定期查詢 SELECT wl_id, COUNT(*) FROM wl_servlet_sessions GROUP BY wl_id HAVING COUNT(*) > 1 發現潛在重複。
  • 遷移:新架構建議改用 Redis / Hazelcast 等分散式 Session 存儲,效能與一致性優於資料庫 JDBC Store。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved