乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
【
乐观锁,大多是基于数据版本 ( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 "version" 字段来实现。
读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
】
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。
【
共享锁(share mode), lock in share mode意向共享锁(IS) 例如select,当上锁之后,另一个线程只可以读,不可以修改。
排他锁(for update), for update意向排它锁(IX)例如update,insert,delete,上锁之后,另一个线程不可以读和修改。
SELECT ... LOCK IN SHARE MODE
在读取到的行上设置共享锁。其他会话可以读取行,也可以继续给行加共享锁,但是在当前事务提交之前其他会话不能修改加了共享锁的行。
如果这些行中的任何一个被尚未提交的另一个事务更改,则当前查询将等待直到该事务结束,然后使用最新值。
SELECT ... FOR UPDATE
用排他锁锁定行和任何关联的索引条目,就像在这些行上执行UPDATE语句一样。
禁止其他事务在这些加了锁的行上进行UPDATE、执行SELECT ... LOCK IN SHARE MODE或者读取某些事务隔离级别的数据。
FOR UPDATE 与 LOCK IN SHARE MODE 都是用于确保被选中的记录值不能被其它事务更新(上锁),
两者的区别在于 LOCK IN SHARE MODE 不会阻塞其它事务读取被锁定行记录的值,而 FOR UPDATE会阻塞其他锁定性读对锁定行的读取(非锁定性读仍然可以读取这些记录,LOCK IN SHARE MODE 和 FOR UPDATE都是锁定性读)。
这么说比较抽象,我们举个计数器的例子:
在一条语句中读取一个值,然后在另一条语句中更新这个值。
使用 LOCK IN SHARE MODE 的话可以允许两个事务读取相同的初始化值,所以执行两个事务之后最终计数器的值+1;(不管事务1提没提交,事务2都可以查询,不会阻塞)
而如果使用 FOR UPDATE的话,会锁定第二个事务对记录值的读取直到第一个事务执行完成,这样计数器的最终结果就是+2了。
注意:锁的前提有两个:1、必须是mysql的innoDb表。2、必须开启transaction事务。两者都有,锁才会生效。
】
锁机制总结
每种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。