死锁与悲观锁乐观锁不是一类东西

Posted InDataBase

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死锁与悲观锁乐观锁不是一类东西相关的知识,希望对你有一定的参考价值。

一般而言,对数据操作会出现以下场景:

 查询自己之前修改的数据

 修改自己之前修改的数据

 查询别人修改的数据(一致性读)

 修改别人修改的数据行(存在锁问题)

 修改别人修改不在同一行的数据块(不存在写一致性问题)

前两组,是单用户操作

后三组,是多用户并发操作

 

对于一致性读,如果有人修改但未提交,Oracle是通过读取回滚段来取得修改之前的数据,来保持数据一致性,避免错读。

对于并发操作,Oracle可以通过悲观锁和乐观锁来解决。

 

 悲观锁

悲观的认为我这段时间内,别人一定会操作数据

虽然别人也可能没人操作,但就是很悲观的认为有人。

所以悲观锁一上来就把我要操作的数据锁住,别人都操作不了。

悲观锁的方法是语句级的(如SQL语句中写上FOR UPDATESQL来实现的。

 

 乐观锁

乐观的认为我这段时间内 没有别人会操作数据

那我们怎么样处理在乐观的情况下,真有人操作数据呢?


一般有2种解决方案

 

1. 使用版本列的乐观锁定

如果我执行以下三步操作,当有人在tttttt时间段进行了数据操作,如果能捕获到,即可进行识别。

select

tttttt

update

 

这是一个简单的实现,如果你想保护数据库表不出现丢失更新问题,应对每个要保护的表增加一列。

这一列一般是NUMBER DATE/TIMESTAMP 列,通常通过表上的一个行触发器来维护。每次修改行时,这个触发器要负责递增NUMBER 列中的值,或者更新DATE/TIMESTAMP 列。

 

例如:

Create table t

(

 Id number,

 Name varhcar2(30),

 Update_time timestamp default systimestamp not null

)


这里增加的列名是update_time

应用只需验证请求更新那一刻,数据库中这一列的值与最初读出的值是否匹配。

如果两个值相等,就说明这一行未被更新过。

 

2. 使用ORA_ROWSCN 的乐观锁定

可以获取某个块最后修改的SCN,甚至可以查到基于行最后一次修改的SCN

通过比较SCN来发现是否有值被别人修改。

适合已经发布的程序,因为不需要增加太多的代码。

 

 

那么死锁是什么?

  

当两个用户分别占有彼此希望对方持有的资源时,而且自己获取的(别人想要的)资源不释放,就会发生死锁。

死锁产生后,Oracle会随机选择一方,对其进行回滚,以解除死锁。

 

这里要区分死锁与等待。

A锁定id=1的记录时,B去锁定id=1的记录,此时B就需要等待,此时B不能进行其他SQL,直到A完成事务。

这种现象叫“等待”。

 

 来个实验就明白了。

先创建测试用的表以及数据


开始执行

 

左侧Session取得了id=1,3的锁

右侧Session取得了id=2,4的锁

左侧Session 要取得id=2的锁,在等待

右侧Session 要取得id=1的锁,此时产生了死锁

Oracle随机选择到了左侧Session,将其进行了回滚。


此时在左侧Session中查询,发现其之前修改id=1,3的数据还在。说明Oracle处理死锁时的回滚是语句级的。

与其他数据库不同,DB2SYBASE等都是事务级的回滚。

同时,右侧的Session要取得id=1的锁,依然在等待。

 

 

悲观锁、乐观锁是为了处理并发的一种解决方案。

处理死锁数据库为防止资源耗尽的一种处理机制。

等待是一个悲观Session的无奈。



翻翻历史,温故知新









以上是关于死锁与悲观锁乐观锁不是一类东西的主要内容,如果未能解决你的问题,请参考以下文章

CAS 与原子操作

乐观锁和悲观锁

MySQLMySQL的乐观锁,悲观锁与MVCC

MySQL:表级锁行级锁共享锁排他锁乐观锁悲观锁

JUC - 多线程之悲观锁乐观锁,读写锁(共享锁独享锁),公平非公平锁,可重入锁,自旋锁,死锁

Mysql:行锁 表锁 乐观锁 悲观锁 读锁 写锁