我们可以用
CONTEXT
. 这是会话内存中的一个命名空间,我们可以使用它来存储值。Oracle提供了默认的名称空间“userenv”,但我们可以定义自己的名称空间。上下文必须由具有创建任何上下文特权的用户创建;这通常是DBA。语句引用了一个在命名空间中设置和获取值的包,但不必存在此包,语句才能成功:
SQL> create context user_ctx using apc.ctx_pkg
2 /
Context created.
SQL>
现在让我们创建包:
SQL> create or replace package ctx_pkg
2 as
3 procedure set_user_id(p_userid in varchar2);
4 function get_user_id return varchar2;
5 procedure clear_user_id;
6 end ctx_pkg;
7 /
Package created.
SQL>
有三种方法可以设置、获取和取消设置命名空间中的值。注意,我们可以使用一个名称空间来保存不同的有效值。我只是使用这个包在用户CTX名称空间中设置一个变量(user_id)。
SQL> create or replace package body ctx_pkg
2 as
3 procedure set_user_id(p_userid in varchar2)
4 is
5 begin
6 DBMS_SESSION.SET_CONTEXT(
7 namespace => 'USER_CTX',
8 attribute => 'USER_ID',
9 value => p_userid);
10 end set_user_id;
11
12 function get_user_id return varchar2
13 is
14 begin
15 return sys_context('USER_CTX', 'USER_ID');
16 end get_user_id;
17
18 procedure clear_user_id
19 is
20 begin
21 DBMS_SESSION.CLEAR_CONTEXT(
22 namespace => 'USER_CTX',
23 attribute => 'USER_ID');
24 end clear_user_id;
25
26 end ctx_pkg;
27 /
Package body created.
SQL>
那么,这是如何解决问题的呢?这是一个临时存储数据的表。我将添加一个列,该列将保存一个令牌来标识用户。当我们填充表时,此列的值将由
CTX_PKG.GET_USER_ID()
:
SQL> create table temp_23 as select * from big_table
2 where 1=0
3 /
Table created.
SQL> alter table temp_23 add (user_id varchar2(30))
2 /
Table altered.
SQL> create unique index t23_pk on temp_23(user_id, id)
2 /
Index created.
SQL>
…在那个表上,我创建了一个视图:…
create or replace view v_23 as
select
id
, col1
, col2
, col3
, col4
from temp_23
where user_id = ctx_pkg.get_user_id
/
现在,当我想在表中存储一些数据时,我需要用一个唯一标识我的用户的值来设置上下文。
SQL> exec ctx_pkg.set_user_id('APC')
PL/SQL procedure successfully completed.
SQL>
此语句用20个随机行填充临时表:
SQL> insert into temp_23
2 select * from
3 ( select b.*, ctx_pkg.get_user_id
4 from big_table b
5 order by dbms_random.random )
6 where rownum <= 20
7 /
20 rows created.
SQL>
我可以通过查询视图来检索这些行。但当我更改我的用户ID并运行相同的查询时,我再也看不到它们:
SQL> select * from v_23
2 /
ID COL1 COL2 COL3 COL4
---------- ---------- ------------------------------ --------- ----------
277834 1880 GV_$MAP_EXT_ELEMENT 15-OCT-07 4081
304540 36227 /375c3e3_TCPChannelReaper 15-OCT-07 36
1111897 17944 /8334094a_CGCast 15-OCT-07 17
1364675 42323 java/security/PublicKey 15-OCT-07 42
1555115 3379 ALL_TYPE_VERSIONS 15-OCT-07 3
2073178 3355 ALL_TYPE_METHODS 15-OCT-07 3
2286361 68816 NV 15-OCT-07 68
2513770 59414 /5c3965c8_DicomUidDoc 15-OCT-07 59
2560277 66973 MGMT_MNTR_CA 15-OCT-07 66
2700309 45890 /6cc68a64_TrustManagerSSLSocke 15-OCT-07 45
2749978 1852 V_$SQLSTATS 15-OCT-07 6395
2829080 24832 /6bcb6225_TypesTypePair 15-OCT-07 24
3205157 55063 SYS_NTsxSe84BlRX2HiXujasKy/w== 15-OCT-07 55
3236186 23830 /de0b4d45_BaseExecutableMember 15-OCT-07 23
3276764 31296 /a729f2c6_SunJCE_n 15-OCT-07 31
3447961 60129 HHGROUP 15-OCT-07 60
3517106 38204 java/awt/im/spi/InputMethod 15-OCT-07 38
3723931 30332 /32a30e8e_EventRequestManagerI 15-OCT-07 30
3877332 53700 EXF$XPVARCLST 15-OCT-07 53
4630976 21193 oracle/net/nl/NetStrings 15-OCT-07 21
20 rows selected.
SQL> exec ctx_pkg.set_user_id('FOX_IN_SOCKS')
PL/SQL procedure successfully completed.
SQL> select * from v_23
2 /
no rows selected
SQL>
因此,面临的挑战是:
建立一个令牌,您可以自动使用它来唯一地标识用户
在连接代码中找到一个钩子,该钩子可以在用户每次得到会话时设置上下文。
同样重要的是,要在断开连接的代码中找到一个钩子,它可以在用户每次离开会话时取消设置上下文。
另外,请记住,一旦用户完成了该表,请将其清除。