兩層 C/S 架構下,用戶操作完畢長時間不斷開佔用連接,導致服務器資源耗盡、性能下降。三層 B/S 可用連接池解決,但傳統架構需後台任務強制清理。
利用動態視圖 V$SESSION 兩個關鍵列:
LOGON_TIME (DATE):登入時間LAST_CALL_ET (NUMBER, 秒):上次調用結束後經過時間,每次新調用歸零SELECT S.USERNAME, S.STATUS, S.MACHINE, S.OSUSER, S.PROCESS,
'ALTER SYSTEM KILL SESSION ''' || S.SID || ',' || S.SERIAL# || '''' KILL_CMD,
S.LOGON_TIME, S.LAST_CALL_ET/60 IDLE_MIN
FROM V$SESSION S, V$PROCESS P
WHERE S.TYPE = 'USER'
AND P.ADDR = S.PADDR
AND S.STATUS != 'KILLED'
-- 排除特殊機器 (跑長報表等)
AND SUBSTR(S.MACHINE,1,19) NOT IN ('REPORT-SERVER-01','BATCH-SERVER-02')
AND S.LAST_CALL_ET > :IDLE_THRESHOLD_MIN * 60
ORDER BY S.LAST_CALL_ET DESC;
CREATE OR REPLACE PROCEDURE P_MONITOR (AN_MINUTES NUMBER DEFAULT 60) AS
V_STR VARCHAR2(200);
CURSOR C_USERS (V_MINUTES NUMBER) IS
SELECT 'ALTER SYSTEM KILL SESSION ''' || S.SID || ',' || S.SERIAL# || '''' KILL_CMD
FROM V$SESSION S, V$PROCESS P
WHERE S.TYPE = 'USER'
AND P.ADDR = S.PADDR
AND S.STATUS != 'KILLED'
-- AND SUBSTR(S.MACHINE,1,19) NOT IN ('排除機器')
AND S.LAST_CALL_ET > V_MINUTES * 60
ORDER BY S.LAST_CALL_ET DESC;
BEGIN
FOR R IN C_USERS(AN_MINUTES) LOOP
V_STR := R.KILL_CMD;
EXECUTE IMMEDIATE V_STR;
END LOOP;
END;
/
-- 必須以 SYS 身份編譯並授權執行
DECLARE
JOBNO NUMBER;
BEGIN
DBMS_JOB.SUBMIT(
JOB => JOBNO,
WHAT => 'P_MONITOR(60);',
NEXT_DATE => SYSDATE,
INTERVAL => 'SYSDATE + 30/1440' -- 30 分鐘 = 30/1440 天
);
COMMIT;
END;
/
-- 驗證
SELECT JOB, WHAT, NEXT_DATE, INTERVAL FROM USER_JOBS;
SYS 下創建/提交,否則 ALTER SYSTEM KILL SESSION 權限不足LAST_CALL_ET 會歸零,不會被誤殺SQLNET.ORA 設置 SQLNET.EXPIRE_TIME = 10 (分鐘) 啟用死連接檢測;資源管理計劃 IDLE_TIME 參數應用層捕獲 ORA-03113/03114 (端到端通信中斷) 異常 → 等待指數退避 → 重新獲取連接池連接 → 重試事務。配合服務端清理形成雙重保障。