Oracle 解決存儲過程包中,kill session的權限問題


一、問題展現

由於本人從事數據中心項目,數據中心有一個共享實例是對外提供數據的,6月11日發現數據庫報ora_12516錯誤,一般ORA-12516有兩個原因,一個是session數不夠
,另一個就是客戶端和服務端建立連接的時候頻繁鏈接數據庫,打開數據庫鏈接而不關閉導致的。

通過plsq工具查詢session,發行從6月9日到6月11日上午,有個用戶頻繁(每隔5分鍾就要鏈接一次)的鏈接數據庫,但是每次鏈接不能釋放,導致用戶該用戶鏈接超過900多,正於是電話溝通業務廠家,讓他們盡快排查關閉鏈接的功能(通過jdbc懷疑沒有關閉鏈接功能或者關閉失效),但是數據庫不能停止,只有自己想辦法(我不是dba,而是開發人員),想起以前給其他項目寫過oracle單機處理殺掉無效進程的過程,於是試試。

二、處理步驟

1、查看數據庫參數

1)查看當前數據庫的processes設置

SQL> show parameter processes


NAME                                 TYPE        VALUE 
db_writer_processes                  integer     1
gcs_server_processes                 integer     0
job_queue_processes                  integer     10
log_archive_max_processes            integer     2
processes                            integer     1200

 

SQL> show parameter sessions
NAME                                 TYPE        VALUE
java_soft_sessionspace_limit         integer     0l
icense_max_sessions                 integer     0
license_sessions_warning             integer     0
logmnr_max_persistent_sessions       integer     1
sessions                             integer     1500
shared_server_sessions               integer

 一般按照經驗值,將processes數設置為1200,則sessions數必須為1.1*1200+5>=1325就行

數據庫參數應該是夠的,但是數據庫不能輕易的改動參數,估計dba來了只有改參數了,但是改參數需要走流程,需要時間還得重啟庫(正式環境重啟需要走流程),於是我覺得在等待業務廠家處理的同時,還是自己寫個kill過程吧,畢竟萬事不求人🐴。

2、編寫存儲過程(代碼為本人知識產權)

在包頭中定義:

CREATE OR REPLACE PACKAGE PKG_SYS IS
PROCEDURE PROC_KILL_INACTIVE_SESSIONS;
PROCEDURE SESSION_LOGS(P_SID IN NUMBER,
P_SERIAL IN NUMBER,
P_INST_ID IN NUMBER,
P_MODULE IN VARCHAR2,
P_STATUS IN VARCHAR2,
P_PROGRAM IN VARCHAR2,
P_MACHINE IN VARCHAR2,
P_LOGIN_TIME IN DATE,
P_MSG IN VARCHAR2,
P_OSUSER IN VARCHAR2);

 

END PKG_SYS;
/

在包體中編寫
CREATE OR REPLACE PACKAGE BODY PKG_SYS IS
/*-------------------------------------------------------------------------------------*/
/* */
/* (C) Copyright IEDS Corporation 2017 All Rights Reserved. */
/* */
/* 函數名稱 :PROC_KILL_INACTIVE_SESSIONS */
/* 功能說明 :殺無效進程 */
/* 參數說明 : */
/* 參數 (I/O) 類型 說明 */
/* 返回值說明 : */
/* 無 */
/* 詳細說明 : */
/* 維度頻率 :無 */
/* ORIGINAL : (1.0) 2017-05-25 CODED BY [IEDS] JINWEI */
/*-------------------------------------------------------------------------------------*/
PROCEDURE PROC_KILL_INACTIVE_SESSIONS AS
V_SID NUMBER;
V_SERIAL NUMBER;
V_INST_ID NUMBER;
V_MODULE VARCHAR2(100);
V_STATUS VARCHAR2(100);
V_PROGRAM VARCHAR2(100);
V_MACHINE VARCHAR2(100);
V_OSUSER VARCHAR2(100);
V_LOGIN_TIME DATE;
V_SQL VARCHAR2(1000);
V_PROC_MSG VARCHAR2(200);
VDAYS NUMBER;

CURSOR C is
select sid,
serial#,
inst_id,
module,
status,
program,
machine,
logon_time,
v.OSUSER
from gv$session v
where type != 'BACKGROUND'
and status IN ('INACTIVE' /*,'KILLED'*/)
and (sysdate - v.LOGON_TIME) > VDAYS
and username = 'share'
and v.PROGRAM like '%JDBC%';
BEGIN
--無效jdbc鏈接天數
VDAYS := 3;
--打開游標
open C;
loop
BEGIN
fetch C
into V_SID,
V_SERIAL,
V_INST_ID,
V_MODULE,
V_STATUS,
V_PROGRAM,
V_MACHINE,
V_LOGIN_TIME,
V_OSUSER;
exit when C%notfound;

V_SQL := 'alter system disconnect session ''' || V_SID || ',' ||
V_SERIAL || ''' immediate';
execute immediate V_SQL;

EXCEPTION
WHEN OTHERS THEN
V_PROC_MSG := 'disconnect SESSION_SID=' || V_SID || ' 失敗:';
V_PROC_MSG := V_PROC_MSG || 'SQLCODE(' || TO_CHAR(SQLCODE) ||
') SQLERRM(' || SUBSTR(SQLERRM, 1, 128) || ')';
--異常日志
SESSION_LOGS(V_SID,
V_SERIAL,
V_INST_ID,
V_MODULE,
V_STATUS,
V_PROGRAM,
V_MACHINE,
V_LOGIN_TIME,
V_PROC_MSG,
V_OSUSER);
END;
--正常日志
V_PROC_MSG := 'disconnect SESSION_SID=' || V_SID || '成功';
SESSION_LOGS(V_SID,
V_SERIAL,
V_INST_ID,
V_MODULE,
V_STATUS,
V_PROGRAM,
V_MACHINE,
V_LOGIN_TIME,
V_PROC_MSG,
V_OSUSER);

end loop;
close C;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END PROC_KILL_INACTIVE_SESSIONS;

--日志表
PROCEDURE SESSION_LOGS(P_SID IN NUMBER,
P_SERIAL IN NUMBER,
P_INST_ID IN NUMBER,
P_MODULE IN VARCHAR2,
P_STATUS IN VARCHAR2,
P_PROGRAM IN VARCHAR2,
P_MACHINE IN VARCHAR2,
P_LOGIN_TIME IN DATE,
P_MSG IN VARCHAR2,
P_OSUSER IN VARCHAR2) AS
-- 定義自動提交事務
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
--刪除3個月前日志
DELETE FROM JC_M_KILL_ORACLE_SESSION_LOGS T
WHERE T.NY <= TO_CHAR(ADD_MONTHS(SYSDATE, -3), 'YYYYMM');
--插入異常日志
INSERT INTO JC_M_KILL_ORACLE_SESSION_LOGS
(sid,
serial,
inst_id,
module,
status,
program,
machine,
logon_time,
SYSTIME,
NY,
MSG,
OSUSER)
SELECT P_SID,
P_SERIAL,
P_INST_ID,
P_MODULE,
P_STATUS,
P_PROGRAM,
P_MACHINE,
P_LOGIN_TIME,
SYSDATE,
TO_CHAR(SYSDATE, 'YYYYMM'),
SUBSTR(P_MSG, 1, 200),
P_OSUSER
FROM DUAL;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE(' || TO_CHAR(SQLCODE) || ') SQLERRM(' ||
SUBSTR(SQLERRM, 1, 128) || ')');
END SESSION_LOGS;

3、問題來了

 1)問題1:

編譯過程 報視圖gv$session 在plsiq過程中不識別,缺乏權限。

 原因:

Oracle為RAC集群機構,在單機可以,集群中gv$session和v$session都需要單獨授權

於是通過操作系統用戶root登錄

su - oracle

sqlplus as / sysdba

grant select on gv$session to A ;

但是 gv$session不能直接授權,需要授權執行視圖的同義詞才行;

grant select on g_v$session to A ;

原因:

我們常用的v$ 是v_$的同義詞,v_$是基於真正的視圖v$,而真正的v$視圖是在gv$的基礎上限制inst_id得到;

我們常用的gv$是gv_$的同義詞,gv_$基於真正的視圖gv$,而真正的gv$視圖基於系統表X$。

2)問題2:

繼續編譯,報錯disconnect SESSION無權限;

 

su - oracle

sqlplus as / sysdba

GRANT ALTER SYSTEM TO A;

到此存儲過程終於可執行了,但是還要增加定時自動執行JOB。

4、定時JOB

每天自動執行一次

begin
sys.dbms_scheduler.create_job(job_name => 'JOB_PROC_KILL_INACTIVE_SESSIONS',
job_type => 'PLSQL_BLOCK',
job_action => 'PROC_KILL_INACTIVE_SESSIONS;',
start_date => to_date('2016-01-02 18:00:00',
'yyyy-mm-dd hh24:mi:ss'),
repeat_interval => 'Freq=Day;Interval=1',
end_date => to_date(null),
job_class => 'DEFAULT_JOB_CLASS',
enabled => true,
auto_drop => false);

end;
/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM