我是一名 .Net Web 开发人员,使用旧版 Oracle 数据库。过去我使用过像 nHibernate 这样的 orm 工具,但是这里的所有数据库通信都需要通过存储过程完成。我们的 dba 要求我们将一堆管理信息传递给我们调用的每个过程,包括最终用户的用户名/域/IP。然后,该数据用于调用另一个存储过程,该存储过程在每次调用过程时记录使用信息。
我不太精通 Oracle 或 Pl/Sql,我正在尝试以干净的方式编写我的 .Net 代码,尽可能满足最佳实践。在我看来,在 .Net 和 Oracle 端将额外数据传递到每个过程的过程都是困惑且乏味的。
有谁知道有没有更好的方法来实现 dba 的目标而不需要所有的开销?或者这是我应该习惯的标准做事方式。
最佳答案
我会使用上下文,而不是向每个存储过程调用传递附加参数。上下文是存储存储过程都可以引用的任意 session 级状态数据的方便位置。
例如,我可以为我的应用程序创建一个上下文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.
同一 session 中的后续调用和查询可以只询问上下文中存储的任何值。
SQL> select sys_context( 'MYAPP_CTX', 'USERNAME' )
2 from dual;
SYS_CONTEXT('MYAPP_CTX','USERNAME')
--------------------------------------------------------------------------------
JCAVE
实际上,您几乎肯定希望向调用 dbms_session.clear_context( 'MYAPP_CTX' )
的包中添加一个 clear_context
过程,以清除已设置的任何值当连接返回到连接池时,避免无意中允许上下文信息从一个 session 渗透到另一个 session 中。您可能还会使用单独的过程来设计包,以设置和获取至少公共(public) key (用户名、IP 地址等),而不是在多个位置硬编码“USERNAME”。为了简单起见,我使用了一个通用 set_value
方法。
关于asp.net - Oracle 存储过程基准测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7984458/