一、什么是锁
Oracle是一个多用户使用的共享资源。当多个用户并发地存取数据时,锁是对数据进行并发控制的机制。Oracle使用锁来保证事务的隔离性,即事务内部的操作和使用的数据对并发执行的其他事务是隔离的、互不干扰的。换言之,锁其实就是事务可以对数据库资源进行操作的权限。
Oracle的事务要执行,必须先申请对该资源的锁,按照获得的锁的不同,就能够对该资源进行锁赋予的操作;如果没有获得锁就不能执行对该资源的任何操作。当某种事件出现或该事务完成后,自动解除对资源的锁。
注意:Oracle所有的锁的管理和分配都是由数据库管理系统自动完成的,不需要用户进行干预,同时也提供了手工加锁的命令,供有经验的用户使用。
二、为什么加锁
作为共享资源的数据库可以供多个用户同时访问,也就是说,在同一时刻,可能会有多个并发执行的事务访问数据库的同一资源。如何保证这些并发事务的执行不破坏数据的一致性和完整性呢?
一种办法就是让所有的事务一个一个串行执行,这样势必大大降低数据库的工作效率。还有一种办法就是提供一种对数据进行并发控制的机制,在同一时刻,可能有的事务获取数据后要进行处理,有的事务仅仅是需要差啊讯该数据而不进行处理,这样查询和调度,这样就能及不破坏数据的一致性,又能大大提高数据库的执行效率。这一种机制就是锁。
三、锁的类型
按照锁的权限来分,Oracle数据库管理系统提供了两种类型的锁,排它锁(Exclusive Lock)和共享锁(Share Lock)。按照锁锁分配的资源来分,又可以分为数据锁(Data Lock)、字典锁(Dictionary Lock)、内部锁、分布所和并行缓存管理所,其中常见的是数据锁和字典锁,其他所都是由管理系统自动管理的。
3.1、按照权限划分
- 排他锁:又称为X锁或写锁。
- 共享锁:又称为S锁或读锁。
3.2、按照资源划分
- 数据锁:当用户对表格中的数据进行INSERT、UPDATE和DELETE操作时将要用到数据锁。数据锁在表中获得并保存数据。
- 字典锁:当用户创建、修改和删除数据表时将要用到字典锁。字典锁用来防止两个用户同时修改同一个表的结构。
四、锁的信息
Oracle在动态状态表v$lock中存储于数据库中的锁有关的所有信息。查看v$lock表的机构:
desc v$lock;
字段含义详解:
(1)SID : 会话标识符
(2)TYPE : 所获得的或等待的锁类型
- Tx事务
- TM DML或表锁
- MR介质恢复
- ST磁盘空间事务
(3)LOMODE/REQUEST : 包含锁的模式
- 0:无
- 1:null空
- 2:Row-S,行共享(RS):共享表锁,sub share
- 3:Row-X,行独占(RX):用于行的修改,sub exclusive
- 4:Share,共享锁(S):阻止其他DML操作,share
- 5:S/Row-X,共享独占(SRX):阻止其他事务操作,share/sub exlusive
- 6:exclusive,独占(X):独立访问使用,exclusive
注意:若LMODE列含有一个不是0或1的数值,则表明进程已经获得了一个锁。若REQUEST列含有一个不是0或1的数值,则表明进程正在等待一个锁。若LMODE列有数值0,则表明进程正等待获得一个锁。
(4)ID1:根据所的类型的不同,此列中的数值有不同的含义。加入锁的类型是TM,那么此列中的数值是将要被锁定的对象的标识;加入锁的类型是TX,那么此列中的数值是回滚段号码的十进制表示。
(5)ID2:根据所的类型的不同,此列中的数值有不同的含义。加入锁的类型是TM,那么此列中的数值是0;加入锁的类型是TX,那么此列表示交换次数,也就是回滚槽重新使用的次数。
五、加锁的方法
5.1、行共享锁RS(Row Share)
通常是通过select … from for update of ... 语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕以后,直接发出rollback命令将锁定解除。当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁,但是允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。
也可以通过如下命令添加行共享锁:
lock table xxx in row share mode;
5.2、行排他锁RX(Row Exclusive)
当我们进行DML时会自动在被更新的表上添加RX锁,或者也可以通过执行lock命令显式的在表上添加RX锁。在该锁定模式下,允许其他的事务通过DML语句修改相同表里的其他数据行,或通过lock命令对相同表添加RX锁定,但是不允许其他事务对相同的表添加排他锁(X锁)。不能使用以下3种方式加锁:
- 行共享锁
- 共享行排他锁
- 行排他锁
lock table xxx in row exclusive mode;
5.3、共享锁S(Share)
对数据表定义共享锁后,其他事务可以执行并发查询和加共享锁但不能修改表,也不能使用以下3中方式加锁:
- 排他锁
- 共享行排他锁
- 行排他锁
lock table xxx in share mode;
5.4、共享行排他锁SPX(Share Row Exclusive)
对数据表定义共享行排他锁后,其他事务可以执行查询和对其他数据行加锁,但不能修改表,也不能使用以下4种方式加锁:
- 共享锁
- 共享行排他锁
- 行排他锁
- 排他锁
lock table xxx in share row exclusive mode;
5.5、排他锁X(Exclusive)
排他锁是最严格的锁。如果被事务A获得,A可以执行对数据表的读写操作,其他事务可以执行查看但不能执行插入、修改和删除操作。
lock table xxx in exclusive mode;
这5种模式的TM锁的兼容关系如下表示(√表示互相兼容的请求;×表示互相不兼容的请求;N/A表示没有锁定请求):
- | S | X | RS | RX | SRX | N/A |
S | √ | × | √ | × | × | √ |
X | × | × | × | × | × | √ |
RS | √ | × | √ | √ | √ | √ |
RX | × | × | √ | √ | × | √ |
SRX | × | × | √ | × | × | √ |
N/A | √ | √ | √ | √ | √ | √ |
前面的描述中可以看到,我们不仅可以通过发出DML语句的方式,由Oracle自动在表级别上添加TM锁。我们还可以通过发出lock table命令主动地在表级别上添加TM锁,并在该命令中可以指定不同的锁定模式,其命令格式如下所示:
lock table in [row share][rowexclusive][share][share row exclusive][exclusive]mode;
对Oracle数据库中的各SQL语句所产生的表级锁的情况进行汇总,如下表所示:
SQL语句 | 表锁定模式 | 允许的表锁定模式 |
Select * from …… | RS | RS、RX、S、SRX、X |
Insert into …… | RX | RS、RX |
Update …… | RX | RS、RX |
Delete from …… | RX | RS、RX |
Select * from for update | RS | RS、RX、S、SRX |
lock table in row share mode | RS | RS、RX、S、SRX |
lock table in row exclusive mode | RX | RS、RX |
lock table in share mode | S | RS、S |
lock table in share row exclusive mode | SRX | RS |
lock table in exclusive mode | X | RS |
对于通过lock table命令主动添加的锁定来说,如果要释放它们,只需要发出rollback命令即可。