Oracle DBMS_会话集_上下文不存储值

Oracle DBMS_会话集_上下文不存储值,oracle,session,global-variables,Oracle,Session,Global Variables,我试图在Oracle中生成一个系统,其中上下文存储一个值;如果在任何会话中更新了表(更新/插入/删除),则应增加该值。我遇到的问题是,即使我确定我已经正确设置了它,它似乎不起作用-上下文似乎没有实际存储值。我正在使用Oracle 11.2.0.1.0 对于最低可能的示例: 我有一个上下文(ACCESSED GLOBALLY子句应使其能够在所有Oracle会话中访问这些值,这正是我想要的): 我有一个调试表: CREATE TABLE DATALOG ( DATALOG_SEQ NUMBER,

我试图在Oracle中生成一个系统,其中上下文存储一个值;如果在任何会话中更新了表(更新/插入/删除),则应增加该值。我遇到的问题是,即使我确定我已经正确设置了它,它似乎不起作用-上下文似乎没有实际存储值。我正在使用Oracle 11.2.0.1.0

对于最低可能的示例:

我有一个上下文(ACCESSED GLOBALLY子句应使其能够在所有Oracle会话中访问这些值,这正是我想要的):

我有一个调试表:

CREATE TABLE DATALOG (
  DATALOG_SEQ NUMBER,
  AT_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  MESSAGE VARCHAR2(4000)
);
我有一个序列来支持
DATALOG
表:

CREATE SEQUENCE SQ_DATALOG;
现在需要PCKG_TESTGLOBALS包,它可以访问
MM_上下文
上下文,并可以更新其中的元素:

CREATE OR REPLACE PACKAGE PCKG_TESTGLOBALS IS

  PROCEDURE Log(FunctionName IN VARCHAR2, Msg IN VARCHAR2);
  PROCEDURE SetParameter(p_name IN VARCHAR2, p_value IN VARCHAR2);

  FUNCTION GetTABLEID RETURN NUMBER;

END PCKG_TESTGLOBALS;
/

CREATE OR REPLACE PACKAGE BODY PCKG_TESTGLOBALS IS

  CONTEXT_NAME CONSTANT VARCHAR2(100) := 'MM_CONTEXT';

  PROCEDURE Log(FunctionName IN VARCHAR2, Msg IN VARCHAR2) IS
    PRAGMA AUTONOMOUS_TRANSACTION;
  BEGIN
    INSERT INTO DATALOG(DATALOG_SEQ, MESSAGE) VALUES (SQ_DATALOG.NEXTVAL, FunctionName || ':' || Msg);
    COMMIT;
  END;

  PROCEDURE SetParameter(p_name IN VARCHAR2, p_value IN VARCHAR2) IS
    ActualValue VARCHAR2(10000);
  BEGIN
    Log('SetParameter', 'ENTERED');
    Log('SetParameter', 'SETTING "' || p_name || '" TO "' || p_value || '"');
    DBMS_SESSION.SET_CONTEXT(CONTEXT_NAME, p_name, p_value);
    ActualValue := SYS_CONTEXT(CONTEXT_NAME, p_name);
    Log('SetParameter', 'READ "' || p_name || '" AS "' || ActualValue || '"');
    Log('SetParameter', 'EXITED');
  END;

  PROCEDURE Initialise IS
    iTmp NUMBER;
  BEGIN
    Log('Initialise', 'ENTERED');
    IF SYS_CONTEXT(CONTEXT_NAME, 'LOWNID') IS NULL THEN
      iTmp := DBMS_RANDOM.RANDOM;
      Log('Initialise', '"LOWNID" has no value, writing "' || iTmp || '"');
      PCKG_TESTGLOBALS.SetParameter('LOWNID', iTmp);
    END IF;
    Log('Initialise', 'EXITED');
  END;

  FUNCTION GetTABLEID RETURN NUMBER IS
    ReadValue VARCHAR2(32767);
  BEGIN
    Log('GetTABLEID', 'ENTERED');
    ReadValue := SYS_CONTEXT(CONTEXT_NAME, 'LOWNID');
    Log('GetTABLEID', 'READ VALUE OF "LOWNID" AS "' || ReadValue || '"');
    Log('GetTABLEID', 'EXITED');
    RETURN TO_NUMBER(ReadValue);
  END;

BEGIN

  Initialise;

END PCKG_TESTGLOBALS;
/
因此,要解释PCKG_TESTGLOBALS中的函数,请执行以下操作:

Log
-出于调试原因记录消息

SetParameter
-获取名称/值对,并使用
DBMS\u会话将其存储。在
MM\u上下文中设置上下文

Initialise
-对于会话变量
LOWNID
,它检查变量是否为空,如果为空,则使用
SetParameter
将其设置为随机值<代码>初始化
在会话中首次使用包时调用

GetTABLEID
-返回会话变量
LOWNID
中存储的值

最后,还有一个名为
TR_ONDML\u TL_LOWN
的触发器,它位于表
LOWN
上,它的结构在这里并不重要,任何表都可以,并且在任何DML、INSERT、UPDATE或DELETE之后触发

CREATE OR REPLACE TRIGGER TR_ONDML_TL_LOWN
  AFTER INSERT OR UPDATE OR DELETE ON LOWN
DECLARE
  iTmp NUMBER;
BEGIN
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'ENTERED');
  iTmp := PCKG_TESTGLOBALS.GetTABLEID;
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'Read Value "' || iTmp || '"');
  iTmp := NVL(iTmp, 1) + 1;
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'Updated Value "' || iTmp || '"');
  PCKG_TESTGLOBALS.SetParameter('LOWNID', iTmp);
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'EXITED');
END TR_ONDML_TL_LOWN;
/
因此,此触发器的目的是:每当更新表
LOWN
时,会话变量
LOWNID
的值将被读回,并将1添加到其中,然后被写回

如果在新会话中,我对
LOWN
表进行了几次连续更新,我会在调试表中得到这些结果(
SELECT MESSAGE FROM DATALOG ORDER BY DATALOG_SEQ


从示例中可以看出,它将值正确地传递给了
DBMS\u SESSION.SET\u CONTEXT
,但它似乎根本没有存储该值。我做错了什么?谢谢。

对于要查看全局可访问上下文的值的会话,其
客户端标识符
(根据
SYS\u上下文('userenv','client\u identifier')
)必须与调用
DBMS\u会话时使用的
client\u id
参数匹配

如果您的
set_context
调用未设置
client_id
它默认为NULL;在这种情况下,只有当会话的
client\u标识符
也为空时,会话才会看到新值

如果会话为
client\u identifier
获取任何特定值,则必须在调用
set\u context
时使用相同的值


在您的情况下,您需要一个所有会话都可以访问的全局变量;如果您的会话为
客户机\u标识符获取随机值,您可能需要在运行代码之前将其设置为NULL,然后(可能)在将控制权返回给调用方之前恢复其值。

奇怪的是,我尝试了这个方法,但仅在pl/sql块中调用了触发器代码,它对我有效。看起来不错。@old程序员我也觉得不错!非常令人沮丧!这是一个全局可访问的上下文,因此需要设置
client\u id
以匹配会话的client\u标识符。如果它们不匹配,上下文将无法检索存储的值。检查会话中的客户端\u标识符。首先,我认为我说必须设置客户端id或用户是不正确的,这只适用于您希望使上下文为各个客户端会话保留单独的值的情况。我认为您应该不设置用户名,但请注意,如果客户端标识符(
SYS\u CONTEXT('userenv','client\u identifier')
)发生更改,会话将看不到值。换句话说,如果会话1碰巧有client\u identifier=123,并且将上下文设置为没有客户端id,它将看不到上下文值。
CREATE OR REPLACE TRIGGER TR_ONDML_TL_LOWN
  AFTER INSERT OR UPDATE OR DELETE ON LOWN
DECLARE
  iTmp NUMBER;
BEGIN
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'ENTERED');
  iTmp := PCKG_TESTGLOBALS.GetTABLEID;
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'Read Value "' || iTmp || '"');
  iTmp := NVL(iTmp, 1) + 1;
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'Updated Value "' || iTmp || '"');
  PCKG_TESTGLOBALS.SetParameter('LOWNID', iTmp);
  PCKG_TESTGLOBALS.Log('TR_ONDML_TL_LOWN', 'EXITED');
END TR_ONDML_TL_LOWN;
/
Initialise:ENTERED
Initialise:"LOWNID" has no value, writing "805223597"
SetParameter:ENTERED
SetParameter:SETTING "LOWNID" TO "805223597"
SetParameter:READ "LOWNID" AS ""
SetParameter:EXITED
Initialise:EXITED
TR_ONDML_TL_LOWN:ENTERED
GetTABLEID:ENTERED
GetTABLEID:READ VALUE OF "LOWNID" AS ""
GetTABLEID:EXITED
TR_ONDML_TL_LOWN:Read Value ""
TR_ONDML_TL_LOWN:Updated Value "2"
SetParameter:ENTERED
SetParameter:SETTING "LOWNID" TO "2"
SetParameter:READ "LOWNID" AS ""
SetParameter:EXITED
TR_ONDML_TL_LOWN:EXITED
TR_ONDML_TL_LOWN:ENTERED
GetTABLEID:ENTERED
GetTABLEID:READ VALUE OF "LOWNID" AS ""
GetTABLEID:EXITED
TR_ONDML_TL_LOWN:Read Value ""
TR_ONDML_TL_LOWN:Updated Value "2"
SetParameter:ENTERED
SetParameter:SETTING "LOWNID" TO "2"
SetParameter:READ "LOWNID" AS ""
SetParameter:EXITED
TR_ONDML_TL_LOWN:EXITED