按用户名终止Oracle会话的存储过程

时间:2014-01-24 18:15:34

标签: oracle stored-procedures plsql oracle11g

网上曾多次询问过这个问题,但我在Google上找到的答案都无法解决我的问题。

我想创建一个杀死Oracle会话的存储过程。过程接受的唯一参数是要杀死的会话的所有者的用户名。

这是我的尝试:

CREATE OR REPLACE PROCEDURE kill_user_session (
    username   IN NVARCHAR2
)
AS
    stmt varchar(5000);
    CURSOR get_sessions
        IS
        SELECT s.sid sid, s.serial# ser
            FROM v$session s, v$process p
        WHERE s.username = username
        AND p.addr(+) = s.paddr;
    session_rec get_sessions%ROWTYPE;
BEGIN
    FOR session_rec in get_sessions LOOP
        BEGIN
            stmt := 'ALTER SYSTEM KILL SESSION ''' || session_rec.sid || ',' ||  session_rec.ser || '''';
            EXECUTE IMMEDIATE stmt;
        --EXCEPTION WHEN others THEN
        --    dbms_output.put_line('Error killing session: ' || stmt);
        --    dbms_output.put_line(SQLERRM);
        END;
    END LOOP;
END;
/

如果我像这样执行

     exec kill_user_session('myuser');

我收到错误:

ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at "SYSTEM.KILL_USER_SESSION", line 17
ORA-06512: at line 1

如果我将第17行更改为

            stmt := 'ALTER SYSTEM KILL SESSION "' || session_rec.sid || ',' ||  session_rec.ser || '"';

然后我得到

ERROR at line 1:
ORA-00026: missing or invalid session ID
ORA-06512: at "SYSTEM.KILL_USER_SESSION", line 17
ORA-06512: at line 1

我已授予SYSTEM以下权利:

GRANT SELECT ON v$session TO SYSTEM;
GRANT ALTER SYSTEM TO SYSTEM;

但这并没有帮助。

编辑:我在执行前添加了dbms_output.putline打印出stmt变量。这是一个例子:

ALTER SYSTEM KILL SESSION "34,91"

如果我在存储过程之外执行此语句,它运行正常并且会话被终止。但不是来自内心。

2 个答案:

答案 0 :(得分:2)

首先,在传递给EXECUTE IMMEDIATE的SQL语句中不应该有分号。这会导致ORA-00911错误。

其次,在执行之前打印出您构建的动态SQL语句总是有帮助的。额外的分号可能是唯一的错误。或者可能存在其他错误。如果您可以看到已构建的SQL语句(并单独执行)而不是仅仅查看构建语句的代码,那么这些错误将不可避免地更容易调试。

答案 1 :(得分:0)

您可以使用以下过程:

{
    CREATE PROCEDURE kill_user_session (users IN VARCHAR2)
    AS
       stmt          VARCHAR (5000);
    
       CURSOR get_sessions
       IS
          SELECT s.sid sid, s.serial# ser
            FROM v$session s, v$process p
           WHERE s.username = users AND p.addr(+) = s.paddr;
    
    BEGIN
       FOR session_rec IN get_sessions
       LOOP
          BEGIN
             stmt :=  'ALTER SYSTEM KILL SESSION ''' || session_rec.sid || ',' || session_rec.ser || '''' || ' IMMEDIATE';
             --dbms_output.put_line(stmt);
             BEGIN
                EXECUTE IMMEDIATE stmt;
                --EXCEPTION WHEN others THEN
          --    dbms_output.put_line('Error killing session: ' || stmt);
          --    dbms_output.put_line(SQLERRM);
             EXCEPTION
                WHEN OTHERS
                THEN
                   -- You probably need to log this error properly here.
                   -- I will just re-raise it.
                   CONTINUE;
             END;
          END;
       END LOOP;
    END;
    /
}