一、悲观锁(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) 应用场景
悲观锁:由于悲观锁会影响系统吞吐的性能,因此适合应用在写为居多的场景下。
乐观锁:由于乐观锁就是为了不悲观锁的弊端出现的,因此适合应用在读为居多的场景下。