乐观锁和悲观锁

一、悲观锁(Pessimistic Concurrency Control),第一眼看到它,相信每一个人都会想到这是一个悲观的锁。没错,它就是一个悲观的锁。mysql

那这个悲观体如今什么地方呢?悲观是咱们人类一种消极的情绪,对应到锁的悲观情绪,悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能变更,一个事务拿到悲观锁后(能够理解为一个用户),其余任何事务都不能对该数据进行修改,只能等待锁被释放才能够执行。sql

数据库中的行锁,表锁,读锁,写锁,以及syncronized实现的锁均为悲观锁。数据库

 

 

 咱们常用的数据库是mysql,mysql中最经常使用的引擎是Innodb,Innodb默认使用的是行锁。而行锁是基于索引的,所以要想加上行锁,在加锁时必须命中索引,不然将使用表锁。安全

 

 

二、 乐观锁(Optimistic Concurrency Control)的“乐观情绪”体如今,它认为数据的变更不会太频繁。所以,它容许多个事务同时对数据进行变更。性能

乐观锁一般是经过在表中增长一个版本(version)或时间戳(timestamp)来实现,其中,版本最为经常使用。spa

事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变更完毕想要将其更新到表中时,会将以前取出的版本v1与数据中最新的版本v2相对比,若是v1=v2,那么说明在数据变更期间,没有其余事务对数据进行修改,此时,就容许事务对表中的数据进行修改,而且修改时version会加1,以此来代表数据已被变更。命令行

若是,v1不等于v2,那么说明数据变更期间,数据被其余事务改动了,此时不容许数据更新到表中,通常的处理办法是通知用户让其从新操做。不一样于悲观锁,乐观锁是人为控制的。code

 

 

 (3)悲观锁实现blog

 

 SQL添加 for update索引

select num from goods where id = 1 for update;

原理图解:

咱们经过开启mysql的两个会话,也就是两个命令行来演示。
一、事务A执行命令给id=1的数据上悲观锁准备更新数据

 

 

 

这里之因此要以begin开始,是由于mysql是自提交的,因此要以begin开启事务,不然全部修改将被mysql自动提交。

二、事务B也去给id=1的数据上悲观锁准备更新数据

 

 

 

咱们能够看到此时事务B再一直等待A释放锁。若是A长期不释放锁,那么最终事务B将会报错,这有兴趣的能够去尝试一下。

三、接着咱们让事务A执行命令去修改数据,让猪肉脯的数量减一,而后查看修改后的数据,最后commit,结束事务。

 

 

 

咱们能够看到,此时最后一个猪肉脯被A买走,只剩0个了。


四、当事务A执行完第3步后,咱们看事务B中出现了什么

 

咱们看到因为事务A释放了锁,事务B就结束了等待,拿到了锁,可是数据此时变成了0,那么B看到后就知道被买走了,就会放弃购买。



(4)乐观锁实现

思路:

        使用乐观锁的解决思路是,咱们认为数据修改产生冲突的几率并不大,多个事务在修改数据的以前先查出版本号,在修改时把当前版本号做为修改条件,只会有一个事务能够修改为功,其余事务则会失败。

demo:

A和B同时将猪肉脯(id=1下面都说是id=1)的数据查出来,而后A先买,A将id=1和version=0做为条件进行数据更新,即将数量-1,而且将版本号+1。

此时版本号变为1。A此时就完成了商品的购买。最后B开始买,B也将id=1和version=0做为条件进行数据更新,可是更新完后,发现更新的数据行数为0,此时就说明已经有人改动过数据,此时就应该提示用户从新查看最新数据购买。

 图解:

 

咱们仍是经过开启mysql的两个会话,也就是两个命令行来演示。

一、事务A执行查询命令,事务B执行查询命令,由于二者查询的结果相同,因此下面我只列出一个截图。

 

 

 

此时A和B均获取到相同的数据

二、事务A进行购买更新数据,而后再查询更新后的数据。

 

 

 

咱们能够看到事务A成功更新了数据和版本号。

 

事务B再进行购买更新数据,而后咱们看影响行数和更新后的数据  

 

 

能够看到最终修改行数为0,数据没有改变。此时就须要咱们告知用户从新处理。

 

(5)乐观锁和悲观锁总结:

悲观锁

 

  • 优势:悲观锁利用数据库中的锁机制来实现数据变化的顺序执行,这是最有效的办法

  • 缺点:一个事务用悲观锁对数据加锁以后,其余事务将不能对加锁的数据进行除了查询之外的全部操做,若是该事务执行时间很长,那么其余事务将一直等待,那势必影响咱们系统的吞吐量。

 

乐观锁

 

  • 优势:乐观锁不在数据库上加锁,任何事务均可以对数据进行操做,在更新时才进行校验,这样就避免了悲观锁形成的吞吐量降低的劣势。

  • 缺点:乐观锁由于是经过咱们人为实现的,它仅仅适用于咱们本身业务中,若是有外来事务插入,那么就可能发生错误。

(6) 应用场景

 

悲观锁:由于悲观锁会影响系统吞吐的性能,因此适合应用在写为居多的场景下。

乐观锁:由于乐观锁就是为了不悲观锁的弊端出现的,因此适合应用在读为居多的场景下。

相关文章
相关标签/搜索