暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

oracle的 lock

原创 哈萨雅琪 2022-05-30
1987


lock的实现原理

锁用于管理对共享资源的并发访问。Oracle 直接将锁作为数据块的属性,存储在数据块首部的ITL中。

Oracle 的锁定过程:

  1. 找到需要锁定的行的地址
  2. 到达那一行
  3. 就地锁住这一行

由于锁是数据的一个属性,所以oracle不需要传统的锁管理器。

悲观锁和乐观锁

悲观锁:在试图更新前就把行锁住了,一直持续到用户提交或者回滚。

乐观锁:所有锁定的操作都延迟到执行更新之前才进行。

oracle默认使用乐观锁。乐观锁相较而言,并发度更高,由于数据块时间戳控制,可能出现“过晚的写”,这种情况下,事务会回滚重启。

锁升级lock escalation和锁转换

锁转换:锁的模式发生改变。

锁升级:降低锁的粒度。例如行锁升级成为表锁。当锁被认为是数据库中的一种稀缺资源而且要避免大量的维护开销时,就会使用锁升级。

Oracle锁的实现不需要开销,所以从来不会进行锁升级,但是会进行锁转换。Oracle会尽量使用粒度最小的锁。锁升级大大增加了死锁的概率。

由于行锁是在最高程度的限制下获得的,所以不需要锁转换。

锁保护的资源

LOCK用于保护数据库中的数据和元数据等资源。LOCK允许并发等待,当请求的LOCK不可获取的时候,会把进程放到请求队列中FIFO。

保护的资源定义:<ResourceType-ID1-ID2>

ID1和ID2由锁的类型决定

TM锁的ID2为0

如何根据ID1计算USN和SLOT?

先转化为8位十六进制

补全前置0:00010007  0001---USN 0007----SLOT

所以65543就是1号UNDO段的7号槽。

资源定义:<ResourceType-ID1-ID2>在V$SESSION_WAIT/V$SESSION里可以观察到对应的值。

其中P1=NAME|MODE、P2=ID1,P3=ID2

将P1转换为可读的值:

select chr(bitand(p1,-16777216)/16777215)||

chr(bitand(p1, 16711680)/65535) "Lock",

bitand(p1, 65535) "Mode"

from v$session_wait

where event = '等待事件名';

ENQUEUE锁可以通过动态性能视图V$LOCK进行观察,而普通的LOCK是不可以的。

锁的原则

只有被修改时,行才会被锁定。

写不会阻塞读,读不会阻塞写,除了SELECT FOR UPDATE。读写同一数据对象的并发控制方法-mvcc.

锁的分类

有些书上把LOCK分为enqueue锁和普通锁。

1.普通锁: row cache lock ,library cache lock ,library cache pin ,buffer lock

2.enqueue 锁:

    • user type lock:TM、TX、UL等
    • system type lock: CF、US、CI、TC、JS等

enqueue锁是以队列结构管理的锁,通过ENQUEUE HASH CHAIN 结构实现的。。访问该链表的时候需要持有LATCH。ENQUEUE HASH CHAIN LATCH与CPU的数目是相等的。

锁模式

ENQUEUE锁的模式有6种:

锁的级别越高,影响的范围就越大。

  • 0--不存在锁
  • 1--空锁,不与任何锁冲突. 可能在SELECT操作的时候产生。正常情况下SELECT 不加锁
  • 2--行级共享锁。可以通过LOCK FOR UPDATE以及LOCK ROW SHARE手动产生
  • 3--行级排他锁。DML语句,也会在SELECT FOR UPDATE产生。
  • 4--表级共享锁。在CREATE 语句的时候,外键锁的常见情况。
  • 5--共享行排他。有主外键约束的时候可能会产生这个锁。可能由4号锁升级而来。

模式4,5出现的时候要考虑在外键上创建索引。

  • 6--排他。产生的原因有ALTER TABLE、DROP TABLE 、DROP INDEX 以及TRUNCATE操作。

锁模式之间能否同时使用被称为模式共享性。这些会对整个表产生影响的操作。锁模式兼容矩阵:

相容的:相加等于6的以及(4,4),(1,6)(6,1)--因为模式为1的锁不阻塞任何锁

对表进行修改的时候会以模式6独占TM锁,对表进行DML操作的进行会占有3号锁,所以允许多个进程同时修改 同一个表。不同类型的锁的容斥互不干扰

select for update:3号TM 6号TX

锁的获取

队列锁获取失败的时候会将自己登记到等待队列里面去。当LOCK的持有者释放LOCK的时候就会唤醒等待队列的其他进程。等待队列中的锁自己设置了一个闹钟,超时的时候自动苏醒,队列锁超时的时间是3秒。每3秒自动醒来一次,看看LOCK的持有者是不是已经发生了死锁,然后重新回到等待队列。如果已经发生了死锁,那么发现死锁的进程会被取消,而且在所有的事务中,只有当前SQL语句会被回滚。并在告警日志中进行记录。这跟LATCH就不一样了,LATCH的等待者只担心持有者异常去世,而LOCK则担心持有者发生了死锁。这是因为LATCH是不会发生死锁的。而LOCK的死锁一般也是因为系统设计问题,是可以避免的。普通锁的工作方式队列锁是一样的,只是不同的锁,超时的时间不同。

死锁

如果有两个会话,每个会话都持有另一个会话想要的资源,就会发生死锁。oracle死锁发生时只会回滚与死锁相关的SQL语句,不会回滚整个事务,牺牲者的选择是随机的(也有些书说,一般是在等待时间最长的会话中产生死锁错误。我这里遵循DSI以及官方文档的说法)。出现死锁的时候会在跟踪文件里面留下信息,

造成死锁的最重要原因是外键没有加索引。

死锁的常见原因:1. 外键没有索引 2. 位图索引上的并发更新。

父表有些情况下会对子表加上一个全表锁:

1、更新了父表的主键,外键一般是父表的主键,父表主键发生了更新,而外键上又没有加索引那么就会在子表上进行修改的。

2、没有外键索引的情况下删除了父表中的某一行。

这些全表锁是短期的,只有在DML期间存在,而不是在整个事务期间存在。

实验:

create table p (x int primary key);

create table c (x references p);

insert into p values(1);

insert into p values(2);

commit;

insert into c values(2);

delete from P where x=1;

这个时候,已经打开的会话可以对C进行DML操作,但是新开会话对C 进行DML会被阻塞。

在查看V$LOCK视图

引起阻塞的会话ID

从这两个图看出来:阻塞者为397号会话,133会话以及20会话被阻塞,都是被397阻塞了。

常见的LOCK

1.TX锁(事务锁)

事务发起第一个修改语句时就会得到一个TX锁,这个锁会被一直持有,直到事务COMMIT或者ROLLBACK。不仅仅是事务修改会产生这个锁,而且SELECT FOR UPDATE也会产生。不论锁定的有多少行,在V$LOCK视图中都只有一行。

TX lock最常见的就是mode=6一直没有提交,或一直在执行

还有一种是TX lock mode=4 ITL:1. 条目没空间扩展2.主键同时被插入3.位图索引被更新

2. TM锁(表锁/ DML锁)

TM锁可以防止另一个会话对表进行DDL操作,包括ALTER 和DROP。确保在修改数据内容时,表的结构不会被修改。

修改了多少个对象,就能得到多少个TM锁。

如果你持有一个TM锁,而其它用户试图在这个表上执行DDL操作时,会报错ORA-54.(也可以通过设置DDL_LOCK_TIMEOUT来让DDL等待,单位秒)。

手动持有锁:LOCK TABLE .....IN .....MODE;(TM锁)

每个事务只能得到一个TX锁,但是修改了多少对象能够得到多少个TM锁。

系统中允许的TM锁个数由DML_LOCK来限制。当DML_LOCK=0时,数据库不允许DDL操作。

DML锁指的是TM锁。

V$LOCK视图

当会话被锁住时,通过V$LOCK视图可以了解当前数据库的锁使用情况。

lmode:当前会话持有的锁模式

request:当前会话请求的锁模式

ctime:拥有或者请求锁的时间。单位秒。

TYPE-区分该锁保护对象的类型。主要关注TX和TM两种类型的锁

  • TM – DML enqueue
  • TX – Transaction enqueue
  • UL – User supplied,UL锁用户自己定义的,一般很少会定义,基本不用关注
  • 其它均为系统锁,会很快自动释放,不用关注

block:当前锁是否阻碍正在执行的另外的锁。0-非blocker ,1-blocker,2-出现在rac种,表示潜在的blocker

一个例子:

这个例子里面,37和36会话BLOCK=1,说明他们是TM锁的持有者,而36和37是被阻塞的会话。37和36持有的锁等级是3,这是一个行排他锁,一个表上是允许多个3号锁的。所以这里出现了2个。而39号会话需要一个6号锁,这是因为他要对表级进行修改,但是呢这个表上已经有某些行被37和36持有了3号行排他锁,6号锁和3号锁不能够共享,所以39号必须等待。

下面以一个TM锁作为例子的,表的OBJECT_ID是823772. 其中SID=37的会话发生了锁转换(mode=4转换为5)

最后修改时间:2022-05-30 11:44:59
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论