`
wutheringsea
  • 浏览: 258808 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Oracle读书摘录3---序列的使用,限制会话,实例与数据库区别

阅读更多

 

1. 对于数据项需递增的问题,正确的解决方法是针对各个数据库使用最合适的代码。在Oracle 中,代码应该如下

(假设表T 需要所生成的主键):

create table t ( pk number primary key, ... );

create sequence t_seq;

create trigger t_trigger before insert on t for each row

begin

select t_seq.nextval into :new.pk from dual;

end;

 

其效果是为所插入的每一行自动地(而且透明地)指定一个惟一键。还有一种性能更优的方法:

Insert into t ( pk, ... ) values ( t_seq.NEXTVAL, ... );

 

也就是说,完全没有触发器的开销(这是我的首选方法)。

在第一个例子中,我们特意使用了各个数据库的特性来生成一个非阻塞、高度并发的惟一键,而且未

对应用代码带来任何真正的改动,因为在这个例子中所有逻辑都包含在DDL 中。

提示在其他数据库中也可以使用其内置的特性或者生成惟一的数来达到同样的效果。CREATE TABLE 语

法可能不同,但是最终结果是一样的。

 

理解了每个数据库会以不同的方式实现特性,再来看一个支持可移植性的防御式编程的例子,这就是

必要时将数据库访问分层。例如,假设你在使用JDBC 进行编程,如果你用的都是直接的S Q L(SELECT、INSERT、

UPDATE 和DELETE),可能不需要抽象层。你完全可以在应用程序中直接编写SQL,前提是只能用各个数据

库都支持的构造,而且经验证,这些构造在不同数据库上会以同样的方式工作(还记得关于NULL=NULL 的

讨论吧!)。另一种方法的可移植性更好,而且可以提供更好的性能,就是使用存储过程来返回结果集。你

会发现,每个开发商的数据库都可以从存储过程返回结果集,但是返回的方式不同。针对不同的数据库,

要编写的具体源代码会有所不同。

这里有两个选择,一种做法是不使用存储过程返回结果集,另一种做法是针对不同的数据库实现不

同的代码。我就坚持第二种做法,即针对不同的开发商编写不同的代码,而且大量使用存储过程。初看上去,另换一个数据库实现时这好像会增加开发时间。不过你会发现,在多个数据库上实现时,采用这种方

法实际上容易得多。你不用寻找适用于所有数据库的最佳SQL(也许在某些数据库上表现好一些,但在另

外一些数据库上可能并不理想),而只需实现最适合该数据库的SQL。这些工作可以在应用之外完成,这样

对应用调优时就有了更大的灵活性。你可以在数据库自身中修正一个表现很差的查询,并立即部署所做的

改动,而无需修改应用。另外,采用这种方法,还可以充分利用开发商提供的SQL 扩缩。例如,Oracle 在

其SQL 中提供了CONNECT BY 操作,能支持层次查询。这个独有的特性对于处理递归查询很有意义。在Oracle

中,你可以自由地使用这个SQL 扩缩,因为它在应用“之外”(也就是说,隐藏在数据库中)。在其他数据

库中,则可能需要使用一个临时表,并通过存储过程中的过程性代码才能得到同样的结果。既然你花钱购

买了这些特性,自然可以充分地加以使用。

 

 

 

2. 通常解决问题的途径有两种:容易的方法和困难的方法。我总是看到人们在选择后者。这并不一定

是故意的,更多的情况下,这么做只是出于无知。他们没想到数据库能“做那个工作”。而我则相反,我

总是希望数据库什么都能做,只有当我发现它确实做不了某件事时才会选择困难的办法(自己来编写)。

例如,人们经常问我,“怎么确保最终用户在数据库中只有一个会话?”(其实类似这样的例子还有

很多,我只是随便选了一个)。可能许多应用都有这个需求,但是我参与的应用都没有这样做,我不知道

有什么必要以这种方式限制用户。不过,如果确实想这样做,人们往往选择困难的方法来实现。例如,他

们可能建立一个由操作系统运行的批作业,这个批作业将查看V$SESSION 表;如果用户有多个会话,就坚

决地关闭这些会话。还有一种办法,他们可能会创建自己的表,用户登录时由应用在这个表中插入一行,

用户注销时删除相应行。这种实现无疑会带来许多问题,于是咨询台的铃声大作,因为应用“崩溃”时不

会将该行删除。为了解决这个问题,我见过许多“有创意的”方法,不过哪一个也没有下面这种方法简单:

ops$tkyte@ORA10G> create profile one_session limit sessions_per_user 1;

Profile created.

ops$tkyte@ORA10G> alter user scott profile one_session;

User altered.

ops$tkyte@ORA10G> alter system set resource_limit=true;

System altered.

ops$tkyte@ORA10G> connect scott/tiger

Connected.

scott@ORA10G> host sqlplus scott/tiger

SQL*Plus: Release 10.1.0.2.0 - Production on Sun Nov 28 12:49:49 2004

Copyright (c) 1982, 2004, Oracle. All rights reserved.

ERROR:

ORA-02391: exceeded simultaneous SESSIONS_PER_USER limit

 

仅此而已。现在有ONE_SESSION 配置文件的所有用户都只能登录一次。每次我提出这个解决方案时,

人们总是拍着自己的脑门,不无惊羡地说:“我不知道居然还能这么做!”正所谓磨刀不误砍柴工,花些时

间好好熟悉一下你所用的工具,了解它能做些什么,在开发时这会为你节省大量的时间和精力。

 

 

 

3.实例是一组后台进程和共享内存。数据库是磁盘上存储的数据集合。实例“一生”只能装载并打开一个数据库。

数据库可以由一个或多个实例(使用RAC)装载和打开。

前面提到过,大多数情况下,实例和数据库之间存在一种一对一的关系。可能正因如此,才导致人们

很容易将二者混淆。从大多数人的经验看来,数据库就是实例,实例就是数据库。

不过,在许多测试环境中,情况并非如此。在我的磁盘上,可以有5 个不同的数据库。测试主机上任

意时间点只会运行一个Oracle 实例,但是它访问的数据库每天都可能不同(甚至每小时都不同),这取决

于我的需求。只需有不同的配置文件,我就能装载并打开其中任意一个数据库。在这种情况下,任何时刻

我都只有一个“实例”,但有多个数据库,在任意时间点上只能访问其中的一个数据库。

所以,你现在应该知道,如果有人谈到实例,他指的就是Oracle 的进程和内存。提到数据库时,则

是说保存数据的物理文件。可以从多个实例访问一个数据库,但是一个实例一次只能访问一个数据库。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics