乐观锁与悲观锁+死锁+所有锁分类

乐观锁 VS 悲观锁

1)悲观锁:就是很悲观,每次去拿数据的时候都认为别人会修改, 所以每次在拿数据的时候都会上锁。这样别人想拿这个数据就会 block 直到它拿到锁。传统的关系型数据库就用到了很多这种机制,比如行锁,写锁等,都是在操作之前上锁。

实现:Synchronized, lock

适用于并发量不大的场景,不会带来很大的性能问题。

2)乐观锁:就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。适用于多读,比如 write_condition. 两种锁各有优缺点,不能认为一种比一种好。

实现:CAS。

乐观锁实现方式:

(1)数据版本

为数据增加一个版本标识,比如增加一个 version 字段。读数据时,将版本号一块儿读出,之后更新时,版本号加 1,将提交数据的版本号与数据库表对应记录的当前版本号进行对比。若提交的大于数据库里面的,则可以更新,否则认为是过期数据。将乐观锁策略在存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据表直接对外公开。

(2)时间戳

在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则冲突。

 

活锁:事务T1封锁数据R,T2又请求封锁R,则T2等待,T3请求封锁R,T3等待,当T1释放了R上的封锁之后系统批准了T3的请求,T2仍然等待,然后T4请求封锁R,T3释放后给了T4,T2继续等待,则产生了活锁现象。

避免活锁:采用先来先服务。

死锁:循环等待锁释放。

预防死锁:

1)一次封锁法:每个事务一次将所有要使用的数据全部加锁。

存在问题:扩大了封锁范围,降低了系统的并发度;由于数据的不断变化,在初始时不能准确定位哪些数据需要加锁,所以只能扩大封锁范围,进一步降低了并发度。

2)顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁。

存在问题:数据太多,要维护封锁顺序非常困难,成本高;封锁请求会不断变化,初始时不能确定哪些事务会封锁数据,所以很难按规定的顺序加封锁。

诊断死锁:

1)超时法:如果一个事务的等待时间超过了规定的时限,则认为发生死锁。

存在问题:出现误判死锁,事务可能因为其他原因使等待时间过长;时限若设置太长,死锁发生后不能及时发现。

2)等待图法:若T2等待T2,则T1,T2之间划一条有向边,从T1指向T2。(与有向图类似)

解除死锁:选择一个处理死锁代价最小的事务,将其撤销,释放此事务持有的所有锁,使其他事务得以继续运行,然后对撤销的事务所执行的数据修改操作必须加以恢复。

 

死锁相关:https://blog.csdn.net/caozhao3344/article/details/77199552

所有锁:https://www.cnblogs.com/qifengshi/p/6831055.html

posted on 2018-04-16 20:32  二十年后20  阅读(418)  评论(0编辑  收藏  举报

导航