oracle锁机制研究
不同于其他数据库,oracle提供了行级锁,在保证数据一致性的情况下极大的提高了并发访问的效率
oracle提供了三中锁模式
Null 主要用于对数据字典对象的访问
Share 锁持有者对资源进行只读访问,允许其他进程并发对资源只读访问
Exclusive 锁持有者对资源进行修改,不允许其他进行对资源做任何访问
对于行级锁,oracle提供了TM锁和TX锁来分别保护表和被修改的数据行
(一)TX锁用于保护当前修改的数据行不被其他并发访问的事务所修改
开启一个会话,修改数据
--会话1
SQL> update t set seq=10 where seq=10;
1 row updated.
我们开启另外一个会话,也修改同一数据行
会话2
SQL> update t set seq=10 where seq=10;
没有任何反应,被阻塞
查询会话等待事件
SQL> select w.SID,w.EVENT from v$session_wait w where w.WAIT_CLASS<>'Idle';
SID EVENT
---------- ----------------------------------------------------------------
48 enq: TX - row lock contention
可以看到会话2被TX锁阻塞,等待TX锁的释放
处理会话1
SQL> commit;
Commit complete.
再观察一下会话2
SQL> update t set seq=10 where seq=10;
1 row updated.
再次进行查询等待时间,发现等待时间消失。
进一步验证了TX主要用来保护数据行不被其他并发访问的事务所修改
(二)TM锁:TM锁用于在并发事务访问过程中保护表的结果,TM锁共有以下五种模式
1、行级排他锁(RX锁)
我们进行DML操作更新表的数据或者显示执行lock table * in row exclusive mode,都会在对应的表上加行级排他锁(RX锁)
该锁定模式允许其他事务修改数据表中的其他数据行,也允许其他并发事务在该表上加RX锁,
但是不允许在该表上加S和X模式的锁
会话1
SQL> lock table t in row exclusive mode;
Table(s) Locked.
会话2
SQL> lock table t in row exclusive mode;
Table(s) Locked.
SQL> lock table t in share mode;
同样在该表上加share模式的锁也产生等待
通过等待事件查询如下:
SQL> select w.SID,w.EVENT from v$session_wait w where w.WAIT_CLASS<>'Idle';
SID EVENT
---------- ----------------------------------------------------------------
10 enq: TM - contention
等待获得TM锁的释放
2、行级共享锁(RS锁)
通常是通过select … from for update语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,
不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕以后,直接发出commit或者rollback命令将锁定解除。
当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁(RX,X,SRX),允许其他事务对表增加RS,S锁,也允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。
会话1
SQL> select * from t where seq=10 for update;
SEQ
----------
10
会话2
SQL> select * from t where seq=10 for update;
产生了等待,同样是等待TM锁的释放
会话1
SQL> lock table t in row share mode;
Table(s) Locked.
会话2
SQL> lock table t in row share mode;
Table(s) Locked.
SQL> lock table t in share mode;
Table(s) Locked.
执行以下三个语句都产生了等待
SQL> lock table t in exclusive mode;
SQL> lock table t in row exclusive mode;
SQL> lock table t in share row exclusive mode;
3、共享锁(S锁)
通过lock table * in share mode对表增加共享锁,不允许并发事务更新该表,也不允许并发对该表增加排他类型的锁(X,RX,SRX),但允许共享模式索引该表(S,RS)
允许其他用户以select * from .. for update锁定该表
会话1
SQL> lock table t in share mode;
Table(s) Locked.
会话2
SQL> lock table t in share mode;
Table(s) Locked.
SQL> lock table t in row share mode;
Table(s) Locked.
添加以下三种模式的锁都产生了等待
SQL> lock table t in exclusive mode;
SQL> lock table t in row exclusive mode;
SQL> lock table t in share row exclusive mode;
同样不允许更新该表数据
SQL> update t set seq=10 where seq=1;
4、排他锁(X)
通过lock table .. in exclusive mode,对表增加拍他锁,这时对该表不能做DML操作,只能做查询,同样不允许并发事务对该表添加任何类型的锁
会话1
SQL> lock table t in exclusive mode;
Table(s) Locked.
其他并发会话的以下所有操作都产生等待
SQL> lock table t in share mode;
SQL> lock table t in row share mode;
SQL> lock table t in share row exclusive mode;
SQL> lock table t in exclusive mode;
SQL> update t set seq=10 where seq=1;
都在等待TM锁的释放
5、共享行级排他锁(SRX)
可以通过lock table .. in share row exclusize mode对表加SRX锁,可以对该表加RS锁,同样并发事务不能对该表加任何模式的锁,
会话1
SQL> lock table t in exclusive mode;
Table(s) Locked.
会话2的以下操作都产生等待
SQL> lock table t in share row exclusive mode;
SQL> lock table t in share mode;
SQL> lock table t in row exclusive mode;
SQL> update t set seq=10 where seq=1;
这五种TM兼容关系如下
- S X RS RX SRX
S √ × √ × ×
X × × × × ×
RS √ × √ √ √
RX × × √ √ ×
SRX × × √ × ×
对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
对于通过lock table命令主动添加的锁定来说,如果要释放它们,只需要发出rollback命令即可。
(三)单实例下oracle锁的类型
根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),
用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构。
当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。
这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率
(四)与锁相关的视图
1、v$lock视图
v$lock视图列出当前系统持有的或正在申请的所有锁的情况,其主要字段说明如下:
字段名称 | 类型 | 说明 |
SID | NUMBER | 会话(SESSION)标识; |
TYPE | VARCHAR(2) | 区分该锁保护对象的类型; |
ID1 | NUMBER | 锁标识1; |
ID2 | NUMBER | 锁标识2; |
LMODE | NUMBER | 锁模式:0(None),1(null),2(row share), 3(row exclusive),4 (share),5(share row exclusive),6(exclusive) |
REQUEST | NUMBER | 申请的锁模式:具体值同上面的LMODE |
CTIME | NUMBER | 已持有或等待锁的时间; |
BLOCK | NUMBER | 是否阻塞其它锁申请;0未阻塞 1 阻塞 |
在rac环境下,block字段值还会多一个数值2,表示rac环境下节点间潜在的锁申请。
两个节点各有一个进程申请锁
节点1
SQL> update t set t.seq=10 where seq=10
1 row updated.
SQL> select * from gv$lock where type='TX';
INST_ID ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------- -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
1 322E2C84 322E2DA0 120 TX 655365 165 6 0 7 2
虽然其他节点并没有修改这一行数据,但是仍然存在block为2的潜在锁申请。
节点2修改这一行数据
SQL> update t set seq=10 where seq=10;
产生等待。
SQL> select * from gv$lock where type='TX';
INST_ID ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------- -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
2 343BAB70 343BAB84 132 TX 524312 230 0 6 59 0
1 322E2C84 322E2DA0 120 TX 524312 230 6 0 187 2
已经有了全局锁申请,但是block字段没有变化。
其中在TYPE字段的取值中,本文只关心TM、TX两种DML锁类型;
关于ID1、ID2,TYPE取值不同其含义也有所不同:
TYPE | ID1 | ID2 |
TM | 被修改表的标识(object_id) | 0 |
TX | 以十进制数值表示该事务所占用的回滚段号与该事务在该回滚段的事务表(Transaction table)中所占用的槽号(slot number,可理解为记录号)。其组成形式为: 0xRRRRSSSS ( RRRR = RBS number, SSSS = slot )。 | 以十进制数值表示环绕(wrap)次数,即该槽(slot)被重用的次数; |
2、v$locked_object视图
v$locked_object视图
v$locked_object视图列出当前系统中哪些对象正被锁定,其主要字段说明如下:
字段名称 | 类型 | 说明 |
XIDUSN | NUMBER | 回滚段号; |
XIDSLOT | NUMBER | 槽号; |
XIDSQN | NUMBER | 序列号; |
OBJECT_ID | NUMBER | 被锁对象标识; |
SESSION_ID | NUMBER | 持有锁的会话(SESSION)标识; |
ORACLE_USERNAME | VARCHAR2(30) | 持有该锁的用户的Oracle用户名; |
OS_USER_NAME | VARCHAR2(15) | 持有该锁的用户的操作系统用户名; |
PROCESS | VARCHAR2(9) | 操作系统的进程号; |
LOCKED_MODE | NUMBER | 锁模式,取值同v$lock视图的LMODE; |
3、dba_blockers和dba_waiters视图虽。
为了方便我们查询会话的阻塞状态,当前会话被那个会话阻塞,哪些会话处于被阻塞,oracle提供dba_blockers和dba_waiters视图,为了能够访问这两个视图,需要执行 $ORACLE_HOME/rdbms/admin/catblock.sql.举例如下
会话1
SQL> update t set seq=10 where seq=10;
会话2
SQL>update t set seq=20 where seq=20;
回到会话1
SQL>update t set seq=20 where seq=20;
会话1被会话2阻塞,通过查询这两个视图
SQL> select * from dba_blockers;
HOLDING_SESSION
---------------
25
只有一列,记录了哪些session持有tx锁导致其他会话阻塞,当前查询得知sid=25的会话阻塞了其他会话持有tx锁
进一步查询dba_waiters可以查询到哪个会话被sid=25的会话阻塞
SQL> SQL> select WAITING_SESSION,HOLDING_SESSION from dba_waiters;
WAITING_SESSION HOLDING_SESSION
--------------- ---------------
28 25
sid=28的会话被sid=25的会话阻塞,我们可以通过
alter system kil session '25,1'
清除25会话之后,发现两个视图中对应记录消失。
当然只是比较简单的情况,具体的生产环境会比较复杂,需要通过关联v$session视图来进一步查看具体的会话信息,连接信息以便及时监控,并联系应用开发人员处理。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7483882/viewspace-762671/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/7483882/viewspace-762671/