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

oracle 锁机制

原创 水煮鱼 2022-08-01
825

保证一个数据同一时间只被一个失误操作 --> 最终保证事物的隔离性

并发场景中,很多连接连接到数据库进行进行操作,不同连接中的事物操作不同的数据

test 表 sal列

会话A

updata test set sal=300 where sal=100

-->buffer cache中数据块的数据是300

-->事物未提交

会话B

updata test set sal=sal*3 where sal=100

为了避免发生数据修改歧义,导致数据不一致,提出锁的机制保证事物隔离性

直到会话A中的事物结束(commit/rollback),则锁释放,资源可以被会话B修改

对于会话B而言,出现的状态叫锁等待,但实际上,我们从数据库角度来看

--> oracle数据块会维持一个队列

队列保证客户端发送请求的资源先到先得

会话A 持有资源

会话B 等待资源

会话C 等待资源

B和C虽然都在等待资源,但一旦资源释放,则优先B使用

队列中越靠后的请求,从客户端来讲,锁等待时间越长


锁粒度:锁对什么对象添加

在数据表上添加锁 --> 表锁

在数据页/数据块上添加所 --> 页锁/块锁

在数据行上添加锁 --> 行锁


Oracle/MySQL这种数据库,我们一般只谈表锁和行锁

客户端在执行操作时,无需关心锁机制

客户端的操作,不用先对数据加锁,然后在操作,然后在释放锁

加锁和释放锁的过程是自动的,客户端仅需要关注自己本身的操作即可

基于语句分析,自动添加粒度最小的锁 --> 行锁


锁升级概念:

Oracle和MySQL都没有锁升级机制

锁升级就是只当处理的数据量较大时,发生锁粒度的改变

行锁 升级 表锁

SQLServer中存在锁升级概念


Oracle中:

DML(数据操纵语言)操作会触发锁机制

DQL(数据查询语言)操作不会触发锁机制

select * from test --> 不触发锁

select * from test for update; --> 手动加锁


自动队列管理:

并发场景中会有不同的事务请求操作相同的数据

此时发生锁冲突,表现在客户端就是锁等待

Oracle内部维持队列,管理锁冲突请求,FIFO


事务处理结束前会一致保持锁定

rollback/commit 标记着事务结束,同时自动释放锁

网络异常导致连接断开,pmon检测到会话异常,回滚数据,自动释放锁


锁是数据库的异常吗?

锁是数据库中保证数据安全的基本机制,作为DBA无需处理锁等待事件。

锁等待是业务逻辑问题,和数据库性能好坏无关


Oracle中的锁

行锁

共享锁

排它锁

表锁

意向共享锁

意向排它锁

update test set sal=300 where id =100

要对test表进行加锁

意向排它锁,先对表进行临时锁定,锁定后,添加基于行的排它锁,释放意向锁



锁类型转换

同一会话中:

select * from test where id =100 --> 不加锁

select * from test where id =100 for update --> 添加share锁(S锁,共享锁)

锁转换 --> S 变成 X

update set sal =300 where id =100 -->添加exclusive锁(X锁 排它锁)

commit/rollback --> 锁自动释放

此时提交,意味着释放锁

队列中的其他会话可以按顺序获取该数据的锁

S锁:共享锁 对数据不能修改,但是可以查看

X锁:排它锁 对数据不能修改,也不能查看

S锁具有兼容性,可以兼容其他S锁

S锁和X锁不兼容


死锁:事务互相锁等待

数据 1000 数据 2000

会话A update 1000 --> 对1000加锁

会话B update 2000 --> 对2000加锁

会话A update 2000 --> 锁等待

会话B update 1000 --> 锁等待

会话A 和 会话B中的事务互相锁等待 --> 死锁

Oracle会自动检测死锁,将先执行的语句kill 掉


SQL> select OBJECT_ID,OBJECT_NAME from test where rownum<5;

OBJECT_ID OBJECT_NAME

---------- ------------------------------

20 ICOL$

46 I_USER1

28 CON$

15 UNDO$


会话A

SQL> update test set OBJECT_NAME='AAA' where OBJECT_ID=20;

1 row updated. --> ICOL$修改为AAA 修改未提交 锁定数据


会话B

SQL> update test set OBJECT_NAME='BBB' where OBJECT_ID=46;

1 row updated. --> I_USER1修改为BBB 修改未提交 锁定数据


会话A

SQL> update test set OBJECT_NAME='CCC' where OBJECT_ID=46;

--> 进入锁等待

--> 会话B锁定OBJECT_ID=46的数据,会话A无法获取锁,发生锁冲突,出现锁等待,等待会话B释放锁


会话B

SQL> update test set OBJECT_NAME='DDD' where OBJECT_ID=20;

--> 进入锁等待

--> 会话A锁定OBJECT_ID=20的数据,会话B无法获取锁,发生锁冲突,出现锁等待,等待会话A释放锁


Oracle会自动检测到这种状态 --> 死锁,将先执行的语句kill,报错如下

会话A

update test set OBJECT_NAME='CCC' where OBJECT_ID=46

*

ERROR at line 1:

ORA-00060: deadlock detected while waiting for resource


会话B

SQL处于等待

会话B中操作OBJECT_ID=20数据的SQL等待会话A中事务结束


会话A

commit或rollback

这里执行rollback


会话B

执行成功

1 row updated.

这里执行 commit


SQL> select OBJECT_ID,OBJECT_NAME from test where rownum<5;


OBJECT_ID OBJECT_NAME

---------- ------------------------------

20 DDD

46 BBB

28 CON$

15 UNDO$


死锁问题是在高并发场景中,业务逻辑设计不当导致的数据块异常

DBA无法解决数据块死锁问题,需要从业务修改SQL

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

评论