Oracle数据库锁机制Lock的介绍

Lock行为概述 Lock用途 Lock模式 Lock转换和升级 Lock持续时间 Locks和Deadlocks

Lock是一种机制,可以防止事务对共享数据的不正确的更新和不正确的修改数据结构,在维护数据的一致性和并发性中,它扮演了一个很重要的角色。

Lock行为概述

根据获得的锁的操作,数据库维护几种不同类型的锁。通常,数据库使用两种类型的锁:排它锁(exclusive locks)和共享锁(share locks)。在诸如行或表之类的资源上,只能获得一个排它锁,但是可以在单个资源上获得多个共享锁。

锁会影响读和写的交互。读是查询资源,而写是修改资源。下面总结了Oracle数据库读和写的锁行为:

当语句修改一行时,事务仅获得改行的锁,通过在行级别锁定表数据,数据库最小化对同样数据的争用; 如果一个事务正在修改一行,那么行锁会阻止其他事务同时对改行的修改; 读操作从不阻塞写操作,除了select…for update语句; 写操作从不阻塞读操作,当行正被写操作修改时,数据库使用undo数据来给读操作提供行的一致性视图;

Lock用途

在单用户数据库中,不需要锁,因为只有一个用户修改信息,然而,当多个用户访问和修改数据时,数据库必须提供一种方法来防止对相同数据的并发修改。Locks实现了下面的需求:

一致性(Consistency):会话正在查看和修改的数据不会被其他会话更改,直到该会话完成; 完整性(Integrity):数据和结构必须以正确的顺序反映对它们的所有更改;

Oracle数据库通过锁机制在事务中提供了数据的并发性、一致性和完整性,锁自动执行,不需要用户参与;

当执行SQL语句时,Oracle数据库自动获得必要的锁,例如,在会话修改数据前,会话必须锁定数据,该锁为会话提供了对数据的独占控制,以便其他事务在锁释放之前不会修改锁定的数据。

由于Oracle数据库的锁机制和事务控制密切相关,应用程序设计人员只需正确的定义事务,Oracle数据库会自动管理锁,用户不需显式的锁定任何资源,尽管Oracle数据库也能使用户手动锁定数据。

Lock模式

Oracle数据库自动使用最低限制适用级别,以提供最高程度的数据并发性,同时也提供了数据完整性。限制级别越低,数据越容易被其他用户访问,反之,限制级别越多,其他事务可获得的锁类型越受限。

Oracle数据库在多用户数据库中使用两种锁模式:

排他锁模式(Exclusive lock mode):该模式防止相关的资源共享,当事务修改数据时,将会获得排它锁。第一个单独锁定资源的事务是唯一可以改变该资源的事务,直到排它锁被释放; 共享锁模式(Share lock mode):该模式根据涉及的操作,相关的资源可以共享。读取数据的多个用户可以共享数据,持有共享锁可以防止需要排它锁的写操作并发访问,一些事务可以在同一资源上获得共享锁。

假想一个事务使用select … for update选择了单个表行,该事物获取了exclusive row lock和row share table lock,row lock允许其他会话修改除了已锁定行之外的任何行,而table lock则防止会话修改表的结构,因此,数据库允许尽可能多的语句执行。

Lock转换和升级

Oracle数据库在必要时执行锁转换。在锁转换中,数据库自动将较低限制的表锁转换为更高限制的。

例如:假设一个事务使用select … for update选择了单个行,然后更新锁定的行,在这种情况下,数据库自动将row share table lock转为row exclusive table lock,在该事务,它对已插入、修改和删除的所有行持有exclusive row locks,因为行锁是在最高限制程度下获得的,因此不需要或执行锁转换。

锁转换不同于锁升级,当多个锁在一个粒度级别(比如行)或数据库将锁提升到更高的粒度级别(比如表)时,就会发生锁升级。如果用户锁定表中许多行,那么一些数据库就会自动将row lock升级到单个表。锁的数量减少了,但是锁定的限制增加了。

Oracle数据库从不升级锁,锁升级容易引发死锁。

Lock持续时间

当事务不再需要资源时,Oracle数据库会自动释放锁。在大多数情况下,数据库持有在事务期间语句获得的锁,这些锁可以防止诸如脏读、丢失更新和来自并发事务的破坏性DDL等破坏性干扰。

当语句commit或rollback时,Oracle数据库会释放事务中语句获得的所有锁,当回滚到savepoint时,也会释放savepoint后获得的锁。然而,只有不等待之前已锁定资源的事务才能获取当前可用资源上的锁,正在等待的事务继续等待,直到所有之前的事务完全提交或回滚。

Locks和Deadlocks

死锁是指两个或多个用户在等待彼此锁定的数据,它阻止事务继续工作。

Oracle数据库自动探测死锁,并通过回滚包含在死锁中的语句来解决它们,释放一组冲突的行锁。数据库返回一个执行statement-level rollback的事务对应的消息。回滚的语句属于探测死锁的事务。通常,发出信号的事务应该被显式回滚,但它可以在等待后重试回滚语句。

当事务显式覆盖Oracle数据库的默认锁定时,最常发生死锁。由于Oracle数据库不会升级锁,也不使用read locks来查询,而是使用row-level的锁,死锁很少发生。

死锁演示:

会话1 会话2 说明
SQL> update emp set sal=1000
2 where empno=7369;

1 row updated.

SQL> update emp set sal=2000
2 where empno=7499;

1 row updated.

会话1和2都拥有一个行级锁;
SQL> update emp set sal=2500
2 where empno=7499;
SQL> update emp set sal=1500
2 where empno=7369;
会话彼此修改对方刚修改过的值,因资源互相被对方占用,故都出现等待;
SQL> update emp set sal=2500
2 where empno=7499;

update emp set sal=2500
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource

 事务1检测到死锁,回滚并返回错误;
SQL> select empno,ename,sal from emp
2 where empno in(7369,7499);

EMPNO ENAME SAL
———- ———- ———-
7369 SMITH 1000
7499 ALLEN 1600

 只回滚上一个事务;
SQL> commit;

Commit complete.

 事务1提交,并结束事务;
 1 row updated.事务2显示已更新一行;
 SQL> commit;

Commit complete.

SQL> select empno,ename,sal from emp
2 where empno in(7369,7499);

EMPNO ENAME SAL
———- ———- ———-
7369 SMITH 1500
7499 ALLEN 2000

事务2提交,并结束事务;

(0)
上一篇 2022年3月22日
下一篇 2022年3月22日

相关推荐