《Oracle数据库管理与维护实战》——2.9 锁

  1. 云栖社区>
  2. 博客>
  3. 正文

《Oracle数据库管理与维护实战》——2.9 锁

异步社区 2017-05-02 10:01:00 浏览1253
展开阅读全文

本节书摘来自异步社区出版社《Oracle数据库管理与维护实战》一书中的第2章,第2.9节,作者: 何伟娜 , 常建功,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.9 锁

Oracle数据库管理与维护实战
为阻止并发事务对数据的一致性破坏,Oracle在系统中锁定不同的数据库资源。数据库锁防止影响另外一些人使用数据库。

锁可分为自动锁和显示锁,当进行数据库操作时,缺省情况下,一个事务会自动获得所有数据库资源所需要的锁。例如,假设开始一项新事务,要更新一个客户的地址,在更新需要的记录行之前,Oracle进行检查,确定有没有其他事务锁定这行记录。如果有其他事务锁定这条记录,Oracle则等待,直到其他事务释放了该记录的锁;如果没有其他记录锁定该记录,则自动为该记录上锁,到该事务提交或回滚这个事务时才释放该锁。

Oracle的缺省锁机制对大多数应用而言已经足够。但也有一些情况下,事务需要显示的锁定数据库操作需要用到的数据。例如,如果要对表中大多数记录行进行更新,而表又很大,那么对整个表锁定比对一行记录锁定更有效。而且,对表进行锁定可以保证对表更新一次完成,中间不需要有锁等待。

Oracle的锁根据对象的级别可以分为表级锁、行级锁等。

2.9.1 锁级别

通常,Oracle有两种锁锁定数据资源:共享锁和排他锁。图2-30显示了共享锁和排他锁的使用。

1.共享锁
数据库资源的共享锁给予一个事务对特定锁资源的共享访问,同时另一事务也可以获得同一资源的共享锁。例如图2-30中,两个事务都具有同一表的共享锁,这就允许不同事务在同一时间更新同一表中不同的记录行。

共享锁允许事务高度并发性,又称共享锁为写锁。然而,事务不能总是为所有类型的资源与操作获得共享锁。例如,图2-30中虽然每个事务都可以同时获得同一个表的共享锁,但该事务对它所更新的行获得排他锁,使其他事务不能更新相同的行,以保护数据安全。

image

2.排他锁
排他锁不同于共享锁的是,排他锁在锁定了某资源后,不允许其他事务获取该资源,例如图2-30中,事务1获得第1行与第2行的排他锁后,另一事务2不可以在事务1提交或回滚前获得相同行的共享锁或排他锁。

排他锁显然比共享锁更严格,排他锁又叫写锁,并发性程度更低。因而,Oracle不自动获取数据库资源的排他锁,除非个别需要使用,如需阻止其他并发事件的破坏性交互。

2.9.2 DML锁

当事务进行DML操作(INSERT、UPDATE、DELETE)时,Oracle自动获得数据库中表与索引的锁。为提高并发性并且防止破坏数据,在DML执行过程中,Oracle可以同时获得行级锁和表级锁。

1.行级锁
当事务插入、更新、删除行时,该事务自动获得该特定行的排他锁。在行级锁锁数据行期间,其他事务不可以对该行更新、删除或修改。举一个例子,当事务中含有以下语句时,Oracle将自动锁定CUSTOMERS表中的行。

SQL>UPDATE sales.customers
SET….
WHERE last_name=’Ellison’ AND first_name = ‘Lawrence’;

如果其他事务在以上事务提交或回滚之前,想更新CUSTOMERS表中的Larry Ellison的记录,Oracle发现该行已被锁定,就会让后来的事务处于等待状态。

在更新记录之前,事务可以使用SELECT…FOR UPDATE语句先行锁定要更新的记录。例如,以下语句将所有的zipcode为95000的记录锁定。

SQL>SELECT * FROM sales.customers
WHERE zipcode=95000
FOR UPDATE
NOWAIT;

当执行以上语句时,如果不能锁定所有满足条件的记录,Oracle会返回控制。如果没有NOWAIT关键字,SELECT…FOR UPDATE语句就会一直处于等待状态,直到获得所有的记录行。

2.表级锁
当事务获得一条记录上的锁时,事务自动获得含该行的表的锁。当事务更新表中一行或多行时,可以使用表级锁,以防止其他DDL操作破坏表更新。

例如,要更新CUSTOMERS表中的一行时,事务获得更新行的排他锁,同时也获得CUSTOMERS的表级锁,将表锁定以防止其他事务修改或删除表。

事务可以在事务进行过程中获得表上的共享锁或排他锁。当事务执行一条基本的DML操作,如INSERT、UPDATE或DELETE时,事务通常给共享锁,但也可以使用排他锁。这时需要用LOCK TABLE在表中显示的指定。例如以下语句就用LOCK TABLE语句获得CUSTOMERS的排他锁。

SQL>LOCK TABLE customers
IN EXCLUSIVE MODE
NOWAIT;

如果Oracle不能立即获得所需要的表级锁,NOWAIT会将控制返回,告知不能立即获得表级锁。如果没有NOWAIT,事务将一直处于等待状态,直到获得表级锁。

Oracle实际上还有几种不同级别的表级锁,这里不再详细介绍,包括行共享、行排他、共享行排他以及排他级别,每个表级锁都比前一个严格。

3.死锁
死锁是Oracle系统应当尽量避免的情形,它是因为资源共享而引起的。产生的原因是两个或多个事务等待需要的某个资源,而又不释放现有的资源。图2-31示意的是死锁发生的 过程。
image
图2-31中,事务1在表的Row #1有一个排他锁并等待事务2释放#2的排他锁,但同时#2具有#1需要的排他锁并且在等待#1释放锁。因而两个事务一直僵持,如果没有外来干预,两个事务将永远僵持下去。

死锁的发生是因为不合理的设计。例如,以下两个事务,每个事务含有对PARTS表的多个更新,结果处于死锁状态,因为它们各自锁定了另一个事务需要的行,如表2-7所示。
image

上述事务的设计容易引起死锁,当事务1和事务2同时执行时,事务1需要锁定id=2的行,而事务2将id=2的行已先行锁定,事务1只能等待事务2释放锁;而事务2又在等待事务1的锁,两个事务进入死循环。我们可以对表2-7加以改进,避免死锁,如表2-8所示。

image

上述表对事务设计进行了改进,在每一个UPDATE语句后面都加COMMIT语句,以及时提交并释放行级锁,这样避免了死锁。Oracle在运行过程中会自动检测死锁,并回滚产生死锁的语句以消除死锁。

2.9.3 DDL锁

前面解释了Oracle自动用于保护DML操作的锁。但在使用CREATE、ALTER与DROP语句时,Oracle也会自动锁定数据。每个DDL操作在它自己的事务中完成,只有在进行DDL操作期间才会使用DDL锁。

1.排他DDL锁
创建、修改或删除数据库对象的DDL语句需要对目标对象使用排他锁。例如,当执行一个ALTER TABLE语句时,要给表増加完整性约束,事务会自动给表加排他锁。在ALTER语句前,其他用户不能修改或删除该表。

2.共享DDL锁
一些DDL语句可以获得数据库对象的共享DDL锁,在数据库对象之间建立相互依赖关系的DDL语句通常需要共享DDL锁。例如,创建包时,包的过程与函数引用许多不同的数据库表:当创建这个包时,事务获得这个包上的排他DDL锁,同时获得所引用锁的共享DDL锁,这个共享DDL锁阻止另一个事务获得所引用表的排他锁,而且防止Oracle在完成包编译前修改或删除包所引用的表。和DML共享锁一样,DDL共享锁不妨碍另一个事务获得同一表的共享DDL锁。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注