数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改;加了共享锁的数据对象可以被其他事务读取,但不能修改。
根据保护对象的不同,Oracle数据库锁可以分为以下几大类:
(1) DML lock(data locks,数据锁):用于保护数据的完整性;
(2) DDL lock(dictionary locks,字典锁):用于保护数据库对象的结构(例如表、视图、索引的结构定义);
(3) Internal locks 和latches(内部锁与闩):保护内部数据库结构;
(4) Distributed locks(分布式锁):用于OPS(并行服务器)中;
(5) PCM locks(并行高速缓存管理锁):用于OPS(并行服务器)中。
在Oracle中最主要的锁是DML(也可称为data locks,数据锁)锁。DML锁的目的在于保证并发情况下的数据完整性。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。如:对表中的任一行加锁时,必须先对它所在的表加意向锁,然后再对该行加锁。这样一来,事务对表加锁时,就不再需要检查表中每行记录的锁标志位了,系统效率得以大大提高。
TM锁(表级锁)类型共有5种,分别称为共享锁(S锁)、排它锁(X锁)、行级共享锁(RS锁)、行级排它锁(RX锁)、共享行级排它锁(SRX锁)
当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。如表1所示。
表1 Oracle的TM锁类型 | |||
锁模式 | 锁描述 | 解释 | SQL操作 |
0 | none |
|
|
1 | NULL | 空 | Select |
2 | SS(Row-S) | 行级共享锁,其他对象只能查询这些数据行 | Select for update、Lock for update、Lock row share |
3 | SX(Row-X) | 行级排它锁,在提交前不允许做DML操作 | Insert、Update、Delete、Lock row share |
4 | S(Share) | 共享锁 | Create index、Lock share |
5 | SSX(S/Row-X) | 共享行级排它锁 | Lock share row exclusive |
6 | X(Exclusive) | 排它锁 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
1. 共享锁(Share Table Lock,S):
加锁语法:Lock Table TableName In Share Mode;
允许的操作:一个共享锁由一个事务控制,仅允许其它事务查询被锁定的表。一个有效的共享锁明确地用Select … For update形式锁定行,或执行Lock Table TableName In Share Mode语法锁定整个表,不允许被其它事务更新。
禁止的操作:一个共享锁由一个事务来控制,防止其它事务更新该表或执行下面的语句:
LOCK TABLE TableName IN SHARE ROW EXCLUSIVE MODE;
LOCK TABLE TableName IN ROW EXCLUSIVE MODE;
2. 排它锁(Exclusive Table Lock,X):
排它锁是在锁机制中限制最多的一种锁类型,允许加排它锁的事务独自控制对表的写权限。
加锁语法:Lock Table TableName In Exclusive Mode;
允许的操作:在一个表中只能有一个事务对该表实行排它锁,排它锁仅允许其它的事务查询该表。
禁止的操作:拥有排外锁的事务禁止其它事务执行其它任何DML类型的语句或在该表上加任何其它类型的锁。
定义排它锁的语法:
LOCK TABLE TableName IN EXCLUSIVE MODE;
3. 行级锁(Row Share Table Lock,RS):
一个行级锁(有时称为Subshare Table Lock,简称SS,子共享锁)需要该事务在被锁定行的表上用update的形式加锁。当有下面语句被执行的时候行级锁自动加在操作的表上。
SELECT . . . FROM TableName. . . FOR UPDATE OF . . . ;
LOCK TABLE TableName IN ROW SHARE MODE;
行级锁(Row Share Table Lock)在锁类型中是限制最少的,也是在表的并发程度中使用程度最高的。
允许的操作:行级共享锁由一个事务控制,允许其它事务查询、插入、更新、删除或同时在同一张表上锁定行。因此其它事务可以同时在同一张表上得到行级锁、共享行级排它锁、行级排它锁、排它锁。
禁止的操作:拥有行级锁的事务不允许其它事务执行排它锁,即:
Lock Table TableName In Exclusive Mode;
4. 行级排它锁(Row Exclusive Table Lock,RX):
行级排它锁(亦称为Subexclusive Table Lock,简称SX,子排它锁)通常需要事务拥有的锁在表上被更新一行或多行。当有下面语句被执行的时候行级排它锁被加在操作的表上。
INSERT INTO TableName. . . ;
UPDATE TableName. . . ;
DELETE FROM TableName. . . ;
LOCK TABLE TableName IN ROW EXCLUSIVE MODE;
行级排它锁比行级锁稍微多一些限制。
允许的操作:行级排它锁由一个事务拥有允许其它事务执行查询、修改、插入、删除或同时在同一张表上锁定行。执有行级排它锁的事务允许其它事务在同一张表上同时得到共享锁和行级排它锁。
禁止的操作:行级排它锁由一个事务拥有防止其它事务手动锁定表来排除其它事务的读写权。因此,其它事务不允许在同一张表上使用以下的语句来执行锁事务。
LOCK TABLE table IN SHARE MODE;
LOCK TABLE table IN SHARE EXCLUSIVE MODE;
LOCK TABLE table IN EXCLUSIVE MODE
5. 共享行级排它锁(Share Row Exclusive Table Lock,SRX):
共享行级排它锁有时也称共享子排它锁(Share Subexclusive Table Lock,SSX),它比共享锁有更多限制。定义共享行级排它锁的语法为:
Lock Table TableName In Share Row Exclusive Mode;
允许的操作:仅允许一个事务在某一时刻得到行级排它锁。拥有行级排它锁事务允许其它事务在被锁定的表上执行查询或使用Select … From TableName For update…来准确在锁定行而不能更新行。
禁止的操作:拥有行级排它锁的事务不允许其它事务有除共享锁外的其它形式的锁加在同一张表上或更新该表。即下面的语句是不被允许的:
LOCK TABLE TableName IN SHARE MODE;
LOCK TABLE TableName IN SHARE ROW EXCLUSIVE MODE;
LOCK TABLE TableName IN ROW EXCLUSIVE MODE;
LOCK TABLE TableName IN EXCLUSIVE MODE;
当Oracle数据库发生TX锁等待时,如果不及时处理常常会引起Oracle数据库挂起,或导致死锁的发生,产生ORA-60的错误。
TX锁等待的分析
Oracle数据库中一般使用行级锁。
当Oracle检测到死锁产生时,中断并回滚死锁相关语句的执行,报ORA-00060的错误并记录在数据库的日志文件alertSID.log中。同时在user_dump_dest下产生了一个跟踪文件,详细描述死锁的相关信息。
在日常工作中,如果发现在日志文件中记录了ora-00060的错误信息,则表明产生了死锁。这时需要找到对应的跟踪文件,根据跟踪文件的信息定位产生的原因。
表2 数据字典视图说明 | ||
视图名 | 描述 | 主要字段说明 |
v$session | 查询会话的信息和锁的信息。 | sid,serial#:表示会话信息。 program:表示会话的应用程序信息。 row_wait_obj#:表示等待的对象,和dba_objects中的object_id相对应。 |
v$session_wait | 查询等待的会话信息。 | sid:表示持有锁的会话信息。 Seconds_in_wait:表示等待持续的时间信息 Event:表示会话等待的事件。 |
v$lock | 列出系统中的所有的锁。 | Sid:表示持有锁的会话信息。 Type:表示锁的类型。值包括TM和TX等。 ID1:表示锁的对象标识。 lmode,request:表示会话等待的锁模式的信 息。用数字0-6表示,和表1相对应。 |
dba_locks | 对v$lock的格式化视图。 | Session_id:和v$lock中的Sid对应。 Lock_type:和v$lock中的type对应。 Lock_ID1: 和v$lock中的ID1对应。 Mode_held,mode_requested:和v$lock中 的lmode,request相对应。 |
v$locked_object | 只包含DML的锁信息,包括回滚段和会话信息。 | Xidusn,xidslot,xidsqn:表示回滚段信息。和 v$transaction相关联。 Object_id:表示被锁对象标识。 Session_id:表示持有锁的会话信息。 Locked_mode:表示会话等待的锁模式的信 息,和v$lock中的lmode一致。 |
解锁及Kill Session:
使用下面的语法查出锁并杀掉Session。
SELECT A.SID,A.SERIAL#,A.USERNAME,B.TYPE FROM V$SESSION A,V$LOCK B WHERE A.SID=B.SID;
ALTER SYSTEM KILL SESSION 'SID,SERIAL#';
一、Oracle数据库的锁类型:
TM锁的兼容性如下:(Y表示兼容,N表示冲突)
1.2 TX锁
1.3 举例说明
查询锁的语句为:
1
|
select
sid,type,id1,lmode,request,block
from
v$
lock
l
where
sid
in
(
select
session_id
from
v$locked_object) and type
in
(
'TM'
,
'TX'
) order
by
1;
|
1.4 DML锁的总结:
2.DDL锁
设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据的一致性和准确性。Oracle数据库封锁方式有三种:共享封锁,独占封锁,共享更新封锁
Oracle RDBMS的封锁类型可分为如下三类:
1、内部级封锁
内部级封锁是用于保护ORACLE内部结构,由系统内部实现,用户不能访问,因此我们不必对此做过多的了解。
2、DDL级封锁(字典/语法分析封锁)
DDL级封锁也是由ORACLE RDBMS来控制,它用于保护数据字典和数据定义改变时的一致性和完整性。它是系统在对SQL定义语句作语法分析时自动地加锁,无需用户干予。字典/语法分析封锁共分三类:
1. 字典操作锁:用于对字典操作时,锁住数据字典,此封锁是独占的,从而保护任何一个时刻仅能对一个字典操作。
2. 字典定义锁:用于防止在进行字典操作时又进行语法分析,这样可以避免在查询字典的同时改动某个表的结构。
3. 表定义锁:用于 一个SQL语句正当访问某个表时,防止字典中与该表有关的项目被修改。
3、DML级封锁
DML级封锁用于控制并发事务中的数据操纵,保证数据的一致性和完整性,其封锁对象可以是表或行。
对用户的数据操纵,Oracle可以自动为操纵的数据进行封锁,但如果有操纵授权,则为满足并发操纵的需要另外实施封锁。DML封锁可由一个用户进程以显式的方式加锁,也可通过某些SQL语句隐含方式实现。
DML锁有如下三种封锁方式:
1. 共享封锁方式(SHARE)
2. 独占封锁方式(EXCLUSIVE)
3. 共享更新封锁(SHARE UPDATE)
其中SHARE,EXCLUSIVE用于表封锁,SHARE UPDATE用于行封锁。
1、共享方式的表封锁
共享方式的表封锁是对表中的所有数据进行封锁,该锁用于保护查询数据的一致性,防止其它用户对已封锁的表进行更更新。其它用户只能对该表再施加共享方式的锁,而不能再对该表施加独占方式的封锁,共享更新锁可以再施加,但不允许持有共享更新封锁的进程做更新。共享该表的所有用户只能查询表中的数据,但不能更新。共享方式的表封锁只能由用户用SQL语句来设置,基语句格式如下:
LOCK TABLE <表名>[,<表名>]... IN SHARE MODE [NOWAIT]
- 1
执行该语句,对一个或多个表施加共享方式的表封锁。当指定了选择项NOWAIT,若该封锁暂时不能施加成功,则返回并由用户决定是进行等待,还是先去执行别的语句。
持有共享锁的事务,在出现如下之一的条件时,便释放其共享锁:
A、执行COMMIT或ROLLBACK语句。
B、退出数据库(LOG OFF)。
C、程序停止运行。
共享方式表封锁常用于一致性查询过程,即在查询数据期间表中的数据不发生改变。
2、独占方式表封锁
独占方式表封锁是用于封锁表中的所有数据,拥有该独占方式表封锁的用户,即可以查询该表,又可以更新该表,其它的用户不能再对该表施加任何封锁(包括共享、独占或共享更新封锁)。其它用户虽然不能更新该表,但可以查询该表。
独占方式的表封锁可通过如下的SQL语句来显示地获得:
LOCK TABLE <表名>[,<表名>].... IN EXCLUSIVE MODE [NOWAIT]
- 1
独占方式的表封锁也可以在用户执行DML语句INSERT、UPDATE、DELETE时隐含获得。
拥有独占方式表封锁的事务,在出现如下条件之一时,便释放该封锁:
A、执行COMMIT或ROLLBACK语句。
B、退出数据库(LOG OFF)
C、程序停止运行。
独占方式封锁通常用于更新数据,当某个更新事务涉及多个表时,可减少发生死锁。
3、共享更新封锁方式
共享更新封锁是对一个表的一行或多行进行封锁,因而也称作行级封锁。表级封锁虽然保证了数据的一致性,但却减弱了操作数据的并行性。行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。
可通过如下的两种方式来获得行级封锁:
- 执行如下的SQL封锁语句,以显示的方式获得:
LOCK TABLE <表名>[,<表名>].... IN SHARE UPDATE MODE [NOWAIT]
- 1
- 用如下的SELECT …FOR UPDATE语句获得:
SELECT <列名>[,<列名>]...
FROM <表名>
WHERE <条件>
FOR UPDATE OF <列名>[,<列名>].....[NOWAIT]
- 1
- 2
- 3
- 4
一旦用户对某个行施加了行级封锁,则该用户可以查询也可以更新被封锁的数据行,其它用户只能查询但不能更新被封锁的数据行.如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式封锁表,一直到提交或复原该事务为止。行锁永远是独占方式锁。
当出现如下之一的条件,便释放共享更新锁:
A、执行提交(COMMIT)语句;
B、退出数据库(LOG OFF)
C、程序停止运行。
执行ROLLBACK操作不能释放行锁。
从上面讲述可见,ORACLE RDBMS的加锁机制,解决了并发事务的相容与互斥问题。相容保证事务的并发性,互斥确保数据的一致性。不同用户锁的相容与互斥关系由下图给出。
其中最后一行最后一列为其它用户提供在不同行上设置SHARE UPDATE锁。但当用户1在某行上进行更新操作时,用户2只有等待用户1提交事务后,才能更新自己所封锁的行。
死锁
封锁虽然能够有效的解决并发操作,但是任何资源的独占都会有死锁的危险。例如:有两个事务T1,T2,T1对数据A施加独占封锁,T2对数据B施加了独占封锁。再假设T1要对数据B加锁,由于B已被T2独占封锁,因此T1置于等待状态,等待B被释放;现在若T2也要对A进行封锁,由于A已被T1独占封锁,因此T2也被置于等待状态。这样就形成了两个事务相互等待的状态,而且永远不能结束,此种情况称为死锁。
在Oracle系统中能自动发现死锁,并选择代价最小的,即完成工作量最少的事务予以撤消,释放该事务所拥有的全部锁,记其它的事务继续工作下去。
从系统性能上考虑,应该尽可能减少资源竞争,增大吞吐量,因此用户在给并发操作加锁时,应注意以下几点:
1. 对于UPDATE和DELETE操作,应只封锁要做改动的行,在完成修改后立即提交。
2. 当多个事务正利用共享更新的方式进行更新,则不要使用共享封锁,而应采用共享更新封锁,这样其它用户就能使用行级锁,以增加并行性。
3. 尽可能将对一个表的操作的并发事务施加共享更新锁,从而可提高并行性。
4. 在应用负荷较高的期间,不宜对基础数据结构(表、索引、簇和视图)进行修改。