我是一名使用旧版Oracle数据库的.Net Web开发人员。在过去,我使用过像nHibernate这样的orm工具,但这里的所有数据库通信都需要通过存储过程来完成。我们的dba要求我们将一堆管理信息传递给我们调用的每个程序,包括最终用户的用户名/域/ ip。然后,此数据用于调用另一个存储过程,该过程在每次调用过程时记录使用信息。
我不熟悉Oracle或Pl / Sql,我试图以干净的方式编写我的.Net代码,尽可能地满足最佳实践。在我看来,将额外数据传递到每个过程的过程在.Net和Oracle两端都是混乱和乏味的。
有没有人知道在没有所有开销的情况下实现dba目标的更好方法?或者这是我应该习惯的标准做事方式。
答案 0 :(得分:3)
我使用上下文而不是将附加参数传递给每个存储过程调用。上下文是存储任意会话级状态数据的便利位置,存储过程可以全部引用它们。
例如,我可以为我的应用程序创建一个上下文MYAPP_CTX
,并创建一个简单的包,让我在上下文中设置我想要的任何值。
SQL> create context myapp_ctx using ctx_pkg;
Context created.
SQL> create package ctx_pkg
2 as
3 procedure set_value( p_key in varchar2, p_value in varchar2 );
4 end;
5 /
Package created.
SQL> create package body ctx_pkg
2 as
3 procedure set_value( p_key in varchar2, p_value in varchar2 )
4 as
5 begin
6 dbms_session.set_context( 'MYAPP_CTX', p_key, p_value );
7 end;
8 end;
9 /
Package body created.
当应用程序从连接池获取连接时,它只需设置所有上下文信息一次。
SQL> begin
2 ctx_pkg.set_value( 'USERNAME', 'JCAVE' );
3 ctx_pkg.set_value( 'IP_ADDRESS', '192.168.17.34' );
4 end;
5 /
PL/SQL procedure successfully completed.
然后,同一会话中的后续调用和查询可以询问上下文中存储的任何值。
SQL> select sys_context( 'MYAPP_CTX', 'USERNAME' )
2 from dual;
SYS_CONTEXT('MYAPP_CTX','USERNAME')
--------------------------------------------------------------------------------
JCAVE
实际上,您几乎肯定希望在调用clear_context
的程序包中添加dbms_session.clear_context( 'MYAPP_CTX' )
过程,以清除在连接返回到连接池时在上下文中设置的任何值避免无意中允许来自一个会话的上下文信息流入另一个会话。您可能还会设计包含单独程序的程序包,并至少获取公共密钥(用户名,IP地址等),而不是让“USERNAME”硬编码多个位置。为简单起见,我使用了一个通用set_value
方法。