悲观锁(Pessimistic Lock)顾名思义,就是很悲观,每次获取数据的时候都认为会修改数据,因此每次在获取数据的时候都会对此条数据进行锁定,也就是mysql数据库的行锁,这样别人每次想拿到这个数据的时候就会block直到他拿到锁,mysql数据库类似的机制还有表锁,读锁,写锁等,都是在操作前先上锁。
乐观锁(Optimistic Lock)顾名思义,就是很乐观,每次获取数据的时候都认为不会修改数据,但是在更新的时候会去判断一下此条数据别人有没有进行更改,常用的方法是版本号机制,也可以使用时间戳进行判断,乐观锁适合写比较少的情况下,即多读类型,这样可以提高系统吞吐量,就像数据库提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有其优缺点,如果是读操作远远大于写操作适合用乐观锁,毕竟省去了锁的开销,如果经常进行写操作使用乐观锁反而会影响系统性能,导致上层应用不断地进行retry,这个时候还是选择悲观锁比较合适。
关于乐观锁两种实现机制
1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。用下面的一张图来说明:
如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。
2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。