DBMS_SESSION包小議(一)

yangtingkun發表於2010-03-18

除了使用ALTER SESSION設定會話的狀態,利用V$SESSION查詢會話狀態,Oracle還提供了PL/SQL介面DBMS_SESSION來查詢和設定會話相關的狀態。

描述UNIQUE_SESSION_IDIS_SESSION_ACTIVE函式。

 

 

一般來說設定會話級的狀態都是透過ALTER SESSION語句,也有個別的例外,比如角色的設定是透過SET語句實現的。Oracle除了提供SQL的方法外,還提供了PL/SQL的介面,DBMS_SESSION包,將會話狀態的設定和查詢整合在這個包中。

首先看一下UNIQUE_SESSION_ID函式:

SQL> SELECT DBMS_SESSION.UNIQUE_SESSION_ID FROM DUAL;

UNIQUE_SESSION_ID
----------------------------------------------------------------
0051466F0001

這個函式很簡單,返回的值在資料庫的一個會話的宣告週期中是唯一確定的。

不過光有這個值似乎沒有什麼意義,因為無法關聯到V$SESSION檢視,因此找不到和會話之前的關係。

檢查這個值,最後四位0001比較可疑,似乎是一個序列號之類的東西,而前面的應該和會話的資訊有關。

顯然這是一個十六進位制的數值,將其轉化為十進位制:

SQL> SELECT TO_NUMBER('0051466F', 'XXXXXXXX') FROM DUAL;

TO_NUMBER('0051466F','XXXXXXXX')
--------------------------------
                         5326447

這個數值也看不出什麼特點,不過既然懷疑這個值和V$SESSION會話有關,而V$SESSION中唯一確定會話資訊的是SIDSERIAL#兩個值,不妨將兩個值都取出來觀察一下:

SQL> SELECT SID, SERIAL#, SID*SERIAL# FROM V$SESSION
  2  WHERE SID IN (SELECT SID FROM V$MYSTAT WHERE ROWNUM = 1);

       SID    SERIAL# SID*SERIAL#
---------- ---------- -----------
        81      18031     1460511

這裡將SIDSERIAL#相乘沒有什麼其他的含義,只是簡單的測試,比較剛才得到的數值比較大,而SIDSERIAL#都是比較小的資料。

而相乘後得到的結果比較有意思,雖然並不等於上面的值,但是顯然和上面的值的資料級是一樣的,而且要小於上面的值。看來上面得到的值很可能就是SIDSERIAL#兩個值構成的:

SQL> SELECT 81*65536 FROM DUAL;

  81*65536
----------
   5308416

SQL> SELECT 81*65536 + 18031 FROM DUAL;

81*65536+18031
--------------
       5326447

選擇65536是因為65536是大於18031且是16的冪的最小值。果然得到的結果就是SID*65536 + SERIAL#

SQL> SELECT SID * 65536 + SERIAL#
  2  FROM V$SESSION
  3  WHERE SID IN
  4  (SELECT SID
  5  FROM V$MYSTAT
  6  WHERE ROWNUM = 1);

SID*65536+SERIAL#
-----------------
          5326447

其實不轉化為10進位制也可以很方便的構造出DBMS_SESSION.UNIQUE_SESSION_ID的結果:

SQL> SELECT LTRIM(TO_CHAR(SID, '0XXX')) || LTRIM(TO_CHAR(SERIAL#, '0XXX')) || '0001' M_ID,
  2  DBMS_SESSION.UNIQUE_SESSION_ID S_ID
  3  FROM V$SESSION
  4  WHERE SID =
  5  (SELECT SID
  6  FROM V$MYSTAT
  7  WHERE ROWNUM = 1);

M_ID           S_ID
-------------- ------------------------------
0051466F0001   0051466F0001

根據UNIQUE_SESSION_ID的結果,可以檢查會話是否存活:

SQL> SET SERVEROUT ON
SQL> DECLARE
  2     V_RESULT BOOLEAN;
  3  BEGIN
  4     V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
  5     IF V_RESULT THEN
  6             DBMS_OUTPUT.PUT_LINE('ACTIVE');
  7     ELSIF NOT V_RESULT THEN
  8             DBMS_OUTPUT.PUT_LINE('NOT ACTIVE');
  9     ELSE
 10             DBMS_OUTPUT.PUT_LINE('NULL RESULT');
 11     END IF;
 12  END;
 13  /
輸入 unqie_session_id 的值:  0051466F0001
原值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
新值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('0051466F0001');
ACTIVE

PL/SQL 過程已成功完成。

重新啟動一個會話:

SQL> SET SQLP 'SQL2> '
SQL2> SELECT DBMS_SESSION.UNIQUE_SESSION_ID FROM DUAL;

UNIQUE_SESSION_ID
--------------------------------------------------------------------------------
00723D6D0001

對這個會話ID執行檢查:

SQL> DECLARE
  2     V_RESULT BOOLEAN;
  3  BEGIN
  4     V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
  5     IF V_RESULT THEN
  6             DBMS_OUTPUT.PUT_LINE('ACTIVE');
  7     ELSIF NOT V_RESULT THEN
  8             DBMS_OUTPUT.PUT_LINE('NOT ACTIVE');
  9     ELSE
 10             DBMS_OUTPUT.PUT_LINE('NULL RESULT');
 11     END IF;
 12  END;
 13  /
輸入 unqie_session_id 的值:  00723D6D0001
原值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
新值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('00723D6D0001');
ACTIVE

PL/SQL 過程已成功完成。

將會話2斷開連線:

SQL2> DISC
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
斷開
SQL2>

再次檢查DBMS_SESSION.IS_SESSION_ALIVE的值:

SQL> DECLARE
  2     V_RESULT BOOLEAN;
  3  BEGIN
  4     V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
  5     IF V_RESULT THEN
  6             DBMS_OUTPUT.PUT_LINE('ACTIVE');
  7     ELSIF NOT V_RESULT THEN
  8             DBMS_OUTPUT.PUT_LINE('NOT ACTIVE');
  9     ELSE
 10             DBMS_OUTPUT.PUT_LINE('NULL RESULT');
 11     END IF;
 12  END;
 13  /
輸入 unqie_session_id 的值:  00723D6D0001
原值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('&UNQIE_SESSION_ID');
新值    4:      V_RESULT := DBMS_SESSION.IS_SESSION_ALIVE('00723D6D0001');
NOT ACTIVE

PL/SQL 過程已成功完成。

需要注意,這裡檢查的值和V$SESSION檢視中STATUS列的值沒有關係,V$SESSION檢視中STATUS列指出當前這個會話是否處於活動狀態,而IS_SESSION_ALIVE的值指出這個會話是否還存在,於當前是否活動無關。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-629866/,如需轉載,請註明出處,否則將追究法律責任。

相關文章