1. 以下是对Oracle 锁定策略的总结:
Oracle 只在修改时才对数据加行级锁。正常情况下不会升级到块级锁或表级锁(不过两段提
交期间的一段很短的时间内除外,这是一个不常见的操作)。
如果只是读数据,Oracle 绝不会对数据锁定。不会因为简单的读操作在数据行上锁定。
2.Oracle 数据库中有两个非常重要的概念。多版本(multi-versioning)一词实质上指Oracle 能够从
数据库同时物化多个版本的数据。
ops$tkyte@ORA10G> create table t 2 as 3 select * 4 from all_users; Table created. ops$tkyte@ORA10G> variable x refcursor ops$tkyte@ORA10G> begin 2 open :x for select * from t; 3 end; 4 / PL/SQL procedure successfully completed. ops$tkyte@ORA10G> delete from t; 28 rows deleted. ops$tkyte@ORA10G> commit; Commit complete. ops$tkyte@ORA10G> print x
在前面的例子中,我创建了一个测试表T,并把ALL_USERS 表的一些数据加载到这个表中。然后在这
个表上打开一个游标。在此没有从该游标获取数据,只是打开游标而已。
注意要记住,Oracle 并不“回答”这个查询。打开游标时,Oracle 不复制任何数据,你可以想想看,
即使一个表有十亿条记录,是不是也能很快就打开游标?没错,游标会立即打开,它会边行进边
回答查询。换句话说,只是在你获取数据时它才从表中读数据。
在同一个会话中(或者也可以在另一个会话中;这同样能很好地工作),再从该表删除所有数据。甚
至用COMMIT 提交了删除所做的工作。记录行都没有了,但是真的没有了吗?实际上,还是可以通过游标获
取到数据。OPEN 命令返回的结果集在打开的那一刻(时间点)就已经确定。打开时,我们根本没有碰过表
中的任何数据块,但答案已经是铁板钉钉的了。获取数据之前,我们无法知道答案会是什么;不过,从游
标角度看,结果则是固定不变的。打开游标时,并非Oracle 将所有数据复制到另外某个位置;实际上是
DELETE 命令为我们把数据保留下来,把它放在一个称为undo 段(undo segment)的数据区,这个数据区
也称为回滚段(rollback segment)。
3.多版本和闪回
考虑以下例子。首先得到一个SCN,这是指系统修改号(System Change Number)或系统提交号
(System Commit Number);这两个术语可互换使用。SCN 是Oracle 的内部时钟:每次发生提交时,这个
时钟就会向上滴答(递增)。实际上也可以使用日期或时间戳,不过这里SCN 很容易得到,而且相当准确:
SQL> var scn number --定义一个记录scn的变量 SQL> exec :scn :=dbms_flashback.get_system_change_number --赋值 PL/SQL procedure successfully completed. SQL> print scn --打印输出当前的scn号 SCN ---------- 7645939 SQL> delete from t; 30 rows deleted. SQL> commit; Commit complete. SQL> flashback table t to scn :scn; --闪回表数据到删除之前的状态 flashback table t to scn :scn * ERROR at line 1: ORA-08189: cannot flashback the table because row movement is not enable
/****注意如果你得到一个错误“ORA-08189: cannot flashback the table because row movement is not
enabled using the FLASHBACK command”(ORA-08189:无法闪回表,因为不支持使用FLASHBACK
命令完成行移动),就必须先执行一个命令:ALTER TABLE EMP ENABLE ROW MOVEMENT。这个命令
的作用是,允许Oracle 修改分配给行的rowid。在Oracle 中,插入一行时就会为它分配一个rowid,
而且这一行永远拥有这个rowid。闪回表处理会对EMP 完成DELETE,并且重新插入行,这样就会
为这些行分配一个新的rowid。要支持闪回就必须允许Oracle 执行这个操作。****/
SQL> alter table t enable row movement; Table altered. SQL> flashback table t to scn :scn; Flashback complete. SQL> select * from t; USERNAME USER_ID CREATED ------------------------------ ---------- -------------- TESTMAN 64 27-4月 -10 BI 63 29-6月 -09 SH 61 29-6月 -09 IX 60 29-6月 -09 OE 59 29-6月 -09 HR 58 29-6月 -09 SCOTT 57 10-3月 -04 MGMT_VIEW 56 10-3月 -04 PM 62 29-6月 -09 WKPROXY 51 10-3月 -04 WKSYS 50 10-3月 -04 USERNAME USER_ID CREATED ------------------------------ ---------- -------------- MDDATA 49 10-3月 -04 SYSMAN 54 10-3月 -04 ANONYMOUS 43 10-3月 -04 XDB 42 10-3月 -04 WK_TEST 53 10-3月 -04 OLAPSYS 46 10-3月 -04 CTXSYS 40 10-3月 -04 MDSYS 36 10-3月 -04 SI_INFORMTN_SCHEMA 35 10-3月 -04 ORDPLUGINS 34 10-3月 -04 ORDSYS 33 10-3月 -04 USERNAME USER_ID CREATED ------------------------------ ---------- -------------- EXFSYS 32 10-3月 -04 WMSYS 23 10-3月 -04 DBSNMP 22 10-3月 -04 DMSYS 37 10-3月 -04 DIP 19 10-3月 -04 OUTLN 11 09-3月 -04 SYSTEM 5 09-3月 -04 SYS 0 09-3月 -04 30 rows selected.