欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Oracle数据库锁机制Lock的介绍

程序员文章站 2022-03-31 10:14:40
Lock行为概述 Lock用途 Lock模式 Lock转换和升级 Lock持续时间 Locks和Deadlocks 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提交,并结束事务;