ORACLE 锁的概念是比较难理解的部分,有些名词比较拗口,同时英文单词也无法表达锁准确的行为。
锁是什么东西? 其实它跟我们日常生活中的锁差不多而已,只是它是在数据库里面进行锁!
事务:事务可以理解为一个工作任务,其中该任务有步骤组成,比如说第一步干啥,接下来干啥。也就是工作流程,操作规范之类的。
并发:要理解为别的工人要工作,好比你的同事,当这个同事跟你的职位一样的。你们工作任务,工作内容基本相同,因此就会发生争执!
锁:就是解决这争执的东西! 这个我们日常生活一样,我们对抽屉上锁,就是防止他人,打开它,被偷,被使用!
锁有以下特性
| 属性 | 独占 | 共享 |
| 自动 | 手动 | |
| 隐式 | 显示 | |
| 升级 | 转换 | |
| 辈观 | 乐观 |
独占和共享 俗称为模式。 简单地说 锁定了某个东西,共享就是该被锁定的东西某些属性可以分享给别的同事。 比如说告诉自己老公,抽屉里里面放了1千美金。在数据库里面比如说我把这行数据上锁了后,你可以读。独占就是上了锁后,就不分享了! 共享 S(share),独占X(eXclusive).
自动和手动 这跟开车自动档和手动档概念差不多。系统自动帮你上锁,好比出门后,随手把门一关,门自动就上锁了,你要开的话,不能直接推开,而是要用钥匙或者密码开锁。这个特性我们日常生活中比较少遇到,只是我在电影院看高科技电影,或者是特工电影里面用手的指纹或者人眼识别的门,开了后自动关闭。
手动上锁 自然是人去上锁或者是应用系统开发人员在代码里上发布了上锁命令
LOCK TABLE TABLE_NAME IN ROW SHARE MODE NOWAIT; --2:RS
LOCK TABLE TABLE_NAME IN SHARE UPDATE MODE; --2:RS
LOCK TABLE TABLE_NAME IN ROW EXCLUSIVE MODE NOWAIT; --3:RX
LOCK TABLE TABLE_NAME IN SHARE MODE; --4:S
LOCK TABLE TABLE_NAME IN SHARE ROW EXCLUSIVE MODE; --5:SRX
LOCK TABLE TABLE_NAME IN EXCLUSIVE MODE NOWAIT; --6:X
那么接下来 为什么需要手动上锁呢? 这是涉及到悲观和乐观特性
悲观大意是你查询出来的数据深怕别人修改,一查出来就上锁。
锁在用户修改之前就发挥作用:
Select ..for update(nowait)
Select * from tab1 for update
用户发出这条命令之后,oracle将会对返回集中的数据建立行级封锁,以防止其他用户的修改。
如果此时其他用户对上面返回结果集的数据进行dml或ddl操作都会返回一个错误信息或发生阻塞。
1:对返回结果集进行update或delete操作会发生阻塞。
2:对该表进行ddl操作将会报:Ora-00054:resource busy and acquire with nowait specified.
乐观的认为数据在select出来到update进取并提交的这段时间数据不会被更改。这里面有一种潜在的危险就是由于被选出的结果集并没有被锁定,是存在一种可能被其他用户更改的可能。因此Oracle仍然建议是用悲观封锁,因为这样会更安全。
锁的乐观可以采用 3个方式来解决更新问题 1 增加个时间字段,2 增加个虚拟字段 做个HASH编码 3 利用系统的SCN数据
其实最近以来 手动上锁已经很少使用了,尤其是在JAVA开发领域中。比如说你查出来自己的存款100美元,10分钟后你存进20美元,再刷新回来看一下,发现依旧是100美元。这时候你大惊了下,难道没有存进去吗?然后你去查了下交易记录,在5分钟前你老婆买了20美元的东西。对现在都是使用日志系统了。这样就增大了数据库系统的并发能力。
要是你使用悲观态度,手动上锁,一查出来就锁定了10分钟。这时候你老婆刷卡买东西,就干着急了,回来就叫你跪搓衣板了!
讲了那么多 其实都是废话,一句话告诉你 把乐观和悲观 手动 显示上锁的特性忘了吧!它已经被淘汰了。
显示上锁,和隐式上锁 也是针对自动和手动来的。手动都是显示,自动都是隐式。
最后谈下锁的升级和转换
在ORACLE 只有转换,在MYSQL SQLSERVER 是升级。从行锁升级到表锁。是什么意思呢? 是这样的 如果你锁定60%的行,那么相当于锁定了整个表,那好我就自动帮你升级到表锁。那是因为SQLSERVER 锁占用一定内存,比如说一行锁只占用1B内存,如果1个亿的表,锁定60%的数据就是6000万 为57MB内存。那么升级到表锁就变会了1B内存了。从而节约了内存。
说白了锁的升级就是粒度的升级,这样带来打击面比较大,也就是阻塞其他同事的工作。比如说一个工作间,你要占用60%的空间来工作,你霸道的把整个工作间都占了,不让其他同事来工作。
而锁的转换 是指 安全等级的升高。比如说从共享升级到独占。事务立即在数据行上获得
独占的行锁并且在表级别获得一个行共享表锁,如果该事务之后修改了数据,表级别的行共享表锁会自动转换成一个行独占表锁,实际是后面讲的 RS->RX 或者是TM(SS)->TM(SX)
总结下 我们这里要记住的是锁的属性有 转换,模式!
,我们要对什么东西上锁来对锁进行分类
比如我们日常生活中的,大门锁,房间门锁,抽屉锁,小盒子锁。
一级分类
事务锁 DML:主要是更新数据,删除,插入,UPDATE时候
字典锁 DDL: 修改表结构,增加字段等
内存锁 MDL: 主要是内存结构,内存中链表。要访问内数据的时候。要加LATCH, MUTEX,INTERNAL
二级分类
DML 主要分成 TX ,TM 锁 (行锁,表锁)
DDL 主分成 DDL和 ADL (字典锁)(解析锁)
MDL 主要分成 LATCH,MUTEX 这两个是实现原理不同而已。
上锁和解锁
从上锁到解锁之间有个时间段,工作任务一开始就把所需要的部分资源上了锁,当工作任务结束后就把锁解了,或者说释放了,反正别的同事可以上锁。 你看这里有两个坑,1是 只是上部分资源的锁,2 是只有工作任务结束才释放锁,解开锁。
为什么不一开始把所有需要的资源上锁呢? 那是考虑的并发,为什么要到工作任务结束后才释放锁呢? 那是考虑到事务的一致性。
这里就埋藏了 死锁的车祸。死锁不是锁,是锁的用错了。关于死锁日后再讲
在第二分类当中,再把锁的属性中的模式 也可以说是级别 S,X带进来。就进一步细分!
DML ->TX (X) TM(X) TM(S) TM(SX) TM(SS) TM(SSX) TM(NULL) TM(0)
DDL-> DDL(X) DDL(S) ADL(S)
MDL- > LATCH(X) LATCH(S) MUTEX(X) MUTEX(S)
你们一看 就知道ORACLE锁的重点在 DML->TM当中!
ORACLE 锁的最小粒度是行级锁,而SQLSERVER是内存页锁 4K大小。
行级锁(row-level lock)的作用是防止两个事务同时修改相同的数据行。当一个事务需要修改一行数据时,就需对此行数据加锁。Oracle 对语句或事务所能获得的行级锁的数量没有限制,Oracle 也不会讲行级锁的粒度升级(lock escalation)。行级锁是粒度最精细的锁,因此行级锁能够提供最好的数据并发访问能力及数据处理能力。
Oracle 同时支持多版本并发访问控制(multiversion concurrency control)及行级锁技术(row-level locking),因此用户只有在访问相同数据行时才会出现竞争,具体来说:
l 读取操作无需等待对相同数据行的写入操作。
l 写入操作无需等待对相同数据行的读取操作
l 写入操作只需等待并发地且针对相同数据行的其它写入操作。
当事务获得了某些数据行上的行级锁时,此事务同时获得了数据行所属表上的表级锁(table lock)。表级锁能够防止系统中并发地执行有冲突的 DDL 操作,避免当前事务中的数据操作被并发地 DDL 操作影响。
行级锁机制:
当一个事务开始时,必须申请一个TX锁,这种锁保护的资源是回滚段、回滚数据块。因此申请也就意味着:用户进程必须先申请到回滚段资源后才开始一个事务,才能执行DML操作。申请到回滚段后,用户事务就可以修改数据了。具体顺序如下:
1、首先获得TM锁,保护事务执行时,其他用户不能修改表结构
2、事务修改某个数据块中记录时,该数据块头部的ITL表中申请一个空闲表项,在其中记录事务项号,实际就是记录这个事务要使用的回滚段的地址(应该叫包含)
3、事务修改数据块中的某条记录时,会设置记录头部的ITL索引指向上一步申请到的表项。然后修改记录。修改前先在回滚段将记录之前的状态做一个拷贝,然后修改表中数据。
4、其他用户并发修改这条记录时,会根据记录头部ITL索引读取ITL表项内容,确认是否事务提交。
5、若没有提交,必须等待TX锁释放
从上面的机制来看,无论一个事务修改多少条记录,都只需要一个TX锁。所谓的“行级锁”其实也就是数据块头、数据记录头的一些字段,不会消耗额外的资源。 从另一方面也证明了,当用户被阻塞时,不是被某条记录阻塞,而是被TX锁堵塞。也正因为这点,很多人也倾向把TX锁称为事务锁。
行锁,也称为TX 锁,是一个表中单个行上的锁。一个事务在被INSERT、UPDATE、DELETE、MERGE、或SELECT ... FOR UPDATE 等语句所修改的每一行上获取一个行锁。行锁一直存在直到事务提交或回滚。行锁主要作为一种排队的机制,以防止两个事务修改相同的行。数据库始终以独占模式锁定修改的行,以便其它事务不能修改该行,直到持有锁的事务提交或回滚。行锁定提供了近乎最细粒度的锁定,并因此提供了近乎最佳的并发性和吞吐量。
如果一个事务因为数据库实例失效而终止,会先进行块级恢复以使行可用,之后进行整个事务恢复。
表级锁(table-level lock)的作用是对并发的 DDL 操作进行访问控制,例如防止在 DML 语句执行期间相关的表被移除。当用户对表执行 DDL 或 DML 操作时,将获取一个此表的表级锁。表级锁不会影响其他并发的 DML 操作。对于分区表来说,表级锁既可以针对整个表,也可以只针对某个分区。
当用户执行以下 DML 语句对表进行修改:INSERT,UPDATE,DELETE,及 SELECT ... FOR UPDATE,或执行 LOCK TABLE 语句时,事务将获取一个表级锁。这些 DML 语句获取表级锁的目的有两个:首先保证自身对表的访问不受其它事务 DML 语句的干扰,其次阻止其它事务中和自身有冲突的 DDL 操作执行。任何类型的表级锁都将阻止对此表的排它DDL 锁(exclusive DDL lock),从而阻止了必须具备排它 DDL 锁才能执行的 DDL 操作。例如,当一个未提交的事务拥有某个表上的锁时,此表就无法被修改定义或被移除。
表级锁具有以下几种模式:行共享(row share,RS),行排它(row exclusive,RX),共享(share,S),共享行排它(share row exclusive,SRX),及排它(exclusive,X)。各种模式的表级锁具有的限制级别决定了其是否能与其他表级锁共处于同一数据表上。
我们回顾下 理解ORACLE锁的分类-02 中的TM 二级分类夹带属性
DML ->TX (X) TM(X) TM(S) TM(SX) TM(SS) TM(SSX)
这样我就形成了个安全等级 除了属性X S 外加 表行粒度的组合形成了4组, RS,RX,S,SRX,X.外加SELECT NULL 1等级 再加 没有的 NONE 0 等级
这样我们对照下
TM(X)=6级 X 表独占;
TM(S)=4级 S (share)
TM(SSX)=5级 ssx(s/row-x)
TM(SS)=2级 SS(ROW-S)
TM(SX)=3级 SX(ROW-X)
.....=0 NONE
....=1 NULL
这里有3组要记的,显得重复记忆。而且日常交流当中这3组都是沟通的载体。
1 级别 ;2 SX;3 R-SX
| 级别 | 粒度+模式 | 易于理解 |
| 2 | SS | RS |
| 3 | SX | RX |
| 4 | S | S |
| 5 | SSX | S/RX |
| 6 | X | X |
这里告诉大家一个小技巧 粒度+模式 当中 前面一个字母表示在表加的锁,后面表示在行加的锁,5级别SSX后面两个字母表示行的, 4和6级别只有一个字母,就没有行的事了
2级别 TM(SS) 行共享(RS) Row Share (RS)
这种锁,表示在表上持有锁的事务在表中有被锁定的行,并打算更新它们。行共享锁是限制最少的表级锁模式,提供在表上最高程度的并发性。
ROW SHARE模式允许同时访问被锁定的表,但是禁止用户以排它方式锁定整个表
SYS@lhrdb S1> LOCK TABLE SCOTT.EMP IN ROW SHARE MODE;
SYS@lhrdb S2> LOCK TABLE SCOTT.EMP IN EXCLUSIVE MODE;
====>>>>> 产生了阻塞
查询2个会话的锁:
SYS@lhrdb S1> SELECT D.SID, D.TYPE, D.ID1, D.ID2, D.LMODE, D.REQUEST, D.CTIME, D.BLOCK
2 FROM V$LOCK D
3 WHERE D.SID IN (114, 6)
4 ORDER BY D.SID, D.TYPE;
SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------- -- ---------- ---------- ---------- ---------- ---------- ----------
6 AE 100 0 4 0 231 0
6 TM 86893 0 2 0 169 1
114 AE 100 0 4 0 378 0
114 TM 86893 0 0 6 144 0
114 TO 79619 1 3 0 376 0
S2>回话ID 114 请求(REQUEST) 安全级别为6的锁
而S1>回话持有(LMODE)2级锁 2与4 不兼容!
3级别 TM(SX) 行独占表锁 Row Exclusive Table Lock (RX)
这种锁通常表示持有锁的事务已更新了表行或发出了SELECT...FOR UPDATE。
一个SX锁允许其它事务并发地查询、插入、更新、删除、锁定在同一个表中其它行。
因此,SX锁允许多个事务对同一个表同时获得SX和子共享表锁。
ROW EXCLUSIE类似于ROW SHARE模式,但是不能应用在SHARE模式中。当update,insert,delete发生时,ROW EXCLUSIVE会自动获得。对应lmode3,row-X (SX) 。
SYS@oratest S1> update scott.emp set sal=sal where empno=7369;
1 row updated.
SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- 21 TM 75335 0 3 0 4 0 21 TX 196620 1097 6 0 4 0
|
当会话1做了修改而没有commit或者rollback时,这里有两个锁,其中一个就是TM3的,一个是TX6的。
4级别 TM(S)共享表锁 Share Table Lock (S)
由某个事务拥有的共享表锁允许其它事务查询,但是更新操作只能在仅有单个事务持有共享表锁时才允许。因为可能有多个事务同时持有共享表锁,所以持有此锁不足以确保一个事务可以修改该表。
SHARE允许同时查询,但是禁止更新被锁定的表,阻止其他DML操作 。对应lmode4,share (S) 。
SYS@oratest S1> lock table scott.emp in share mode;
SYS@oratest S2>
select distinct sid from v$mystat;
SID
----------
142
SYS@oratest S2> update scott.emp set sal=sal where empno=7369;
从这里可以看到 会话1 把整个表上了4级别表共享锁 TM(S),其他回话只能查询,不能DML。
查看锁:
SYS@oratest S1> select * from v$lock where sid in (21,142) AND TYPE IN ('TX','TM');
SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK
----- ---- ---------- ---------- ---------- ---------- ---------- ----------
142 TM 75335 0 0 3 43 0
21 TM 75335 0 4 0 62 1
SYS@oratest S1> SELECT * FROM DBA_DML_LOCKS;
SESSION_ID OWNER NAME MODE_HELD MODE_REQUESTE LAST_CONVERT BLOCKING_OTHERS
---------- -------- ------ ------------- ------------- ------------ ---------------
142 SCOTT EMP None Row-X (SX) 113 Not Blocking
21 SCOTT EMP Share None 132 Blocking
5级别 TM(SSX)共享行独占表锁 Share Row Exclusive Table Lock (SRX)
这种锁也称为共享行排他表级锁(SSX,share-subexclusive table lock),比共享表锁的限制性更强。一次只能有一个事务可以获取给定的表上的SSX锁。由某个事务拥有的SSX锁允许其它事务查询该表(除SELECT...FOR UPDATE)但不能更新该表。
共享行级排它锁有时也称共享子排它锁(Share Subexclusive Table Lock,SSX),它比共享锁有更多限制。定义共享行级排它锁的语法为:
Lock Table TableName In Share Row Exclusive Mode;
其实这里按我的方法说 SSX SRX 都不对 应该是 XRS TM(XS) 表上了独占锁,行上了共享锁,后来事务不能作用于表了,当可以读去行.通过lock table in share mode命令添加该S锁。在该锁定模式下,不允许任何用户更新表。也不允许其他用户发出select …from for update命令对表添加RS锁.通过lock table in share row exclusive mode命令添加SRX锁。该锁定模式比行级排他锁和共享锁的级别都要高,这时不能对相同的表进行DML操作,也不能添加共享锁。
我们先看下实验
SYS@oratest S1> lock table scott.emp in share row exclusive mode;
| SID | TYPE | ID1 | ID2 | LOCK_TYPE | REQUEST | CTIME | BLOCK |
| 628 | TM | 73201 | 0 | Share Row Exclusive | 0 | 4 | 0 |
| 628 | TX | 655369 | 42187 | Exclusive | 0 | 4 | 0 |
开启第二个回话,可以查询,不能更新DML了
select * from scott.emp;
update SCOTT.EMP SET SAL=900 WHERE EMPNO=7369
查看锁:
| SID | TYPE | ID1 | ID2 | LOCK_TYPE | REQUEST | CTIME | BLOCK |
| 628 | TM | 73201 | 0 | Share Row Exclusive | 0 | 139 | 1 |
| 223 | TM | 73201 | 0 | None | 3 | 5 | 0 |
| 628 | TX | 655369 | 42187 | Exclusive | 0 | 139 | 0 |
6级别 TM(X)独占表锁 Exclusive Table Lock (X)
这种锁是最严格的锁,禁止其它事务执行任何类型的DML语句,或在表上放置任何类型的锁。
EXCLUSIVE EXCLUSIVE permits queries on the locked table but prohibits any other activity on it.
EXCLUSIVE模式允许查询被锁表上的数据,但是禁止任何其他任何活动(这里我理解是禁止添加其他任何模式的锁)。对应lomde6,exclusive (X) 。通过lock table in exclusive mode命令添加X锁。在该锁定模式下,其他用户不能对表进行任何的DML和DDL操作,该表上只能进行查询。
锁的不兼容模式:
| 级别 | 粒度模式 | TM(SS)|RS | TM(SX)|RX | TM(S)|S | TM(XS)|XRS | TM(X)|X |
| 2 | TM(SS)|RS | X | ||||
| 3 | TM(SX)|RX | X | X | X | ||
| 4 | TM(S)|S | X | X | X | ||
| 5 | TM(XS)|XRS | X | X | X | X | |
| 6 | TM(X)|X | X | X | X | X | X |
我们一般DML操作的时候基本都是处于 2和3的级别,也就是RS,RX 或者SS,SX模式。我们看下下面的表,了解下实际应用会产生什么模式的锁!
DML锁分类表
表1 Oracle的TM锁类型 | |||
锁模式 | 锁描述 | 解释 | SQL操作 |
0 | none | ||
1 | NULL | 空 | Select |
2 | SS(RS) | 行级共享锁,其他对象只能查询这些数据行 | Select for update、Lock for update、Lock row share |
3 | SX(RX) | 行级排它锁,在提交前不允许做DML操作 | Insert、Update、Delete、Lock row share |
4 | S() | 共享锁 | Create index、Lock share |
5 | XS(XRS) | 共享行级排它锁 | Lock share row exclusive |
6 | X() | 排它锁 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
总结下 4,5,6级别 都会阻止DML的操作(INSERT,UPDATE,DELETE)
4级别的S锁 可以有多个,比如说建多个索引,或者说多个索引同时在建。但是它要阻止对该表的DML事务的操作加锁。
5级别主要的目的是阻止别人加4级别的S锁。
6级别主要是除了阻止所有的事务还要阻止DDL锁。
3级别的RX锁 不会阻止其他事务的加RX锁,当会阻止本行加RX,RS锁。
| 级别 | TM | 操作 | 阻止 |
| 2 | SS | ||
| 3 | SX | Insert,update,delete | 同行的SS,SX |
| 4 | S | CREAT INDEX | 所有的DML |
| 5 | XS | lock table in share row exclusive mode | 阻止共享锁 |
| 6 | X | Alter table、Drop able、Drop index、Truncate table | 阻止2-5和DDL |
其实我们关心的是 你加锁会阻止别人,而不关心你加锁想干什么事!也许你人工加X锁,只是查询下数据而已。
总结下 TX 和TM 都属于队列锁序列当中。
如果本号文对你有意义可以下我打赏,金额多少无所谓!
理科精华
文史经典
财经经典




