Redis中的乐观锁和悲观锁

一、定义:

悲观锁(Pessimistic Lock):
  顾名思义,就是很悲观。每次获取数据的时候,都会担心数据被修改,所以每次获取数据的时候都会进行加锁,确保在自己使用的过程中数据不会被别人修改,使用完成后进行数据解锁。由于数据进行加锁,期间对该数据进行读写的其他线程都会进行等待。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等。都是在操作之前先上锁让别人无法操作该数据。

乐观锁(Optimistic Lock):
  顾名思义,就是很乐观。每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据库中的数据时需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。
  一般使用版本号机制进行判断。乐观锁大多数情况是基于数据版本号(version)的机制实现的。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个“version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据,不予更新。

二、乐观锁举例:

Redis中的乐观锁和悲观锁_第1张图片

三、适用场景:

  悲观锁:比较适合写入操作比较频繁的场景,如果出现大量的读取操作,每次读取的时候都会进行加锁,这样会增加大量的锁的开销,降低了系统的吞吐量。

  乐观锁:比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。

总结:两种所各有优缺点,读取频繁使用乐观锁,写入频繁使用悲观锁。

  像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁.

  悲观锁比较适合强一致性的场景,但效率比较低,特别是读的并发低。乐观锁则适用于读多写少,并发冲突少的场景。

四、Redis的watch机制实现乐观锁

  监视一个(或多个) key ,如果在事务exec执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
  下面这个例子:我们在观察的时候k1值为1,但是事务执行的时候k1值为2,k1被修改了所以不能执行事务。

127.0.0.1:6379> set k1 1 #设置k1值为1
OK
127.0.0.1:6379> WATCH k1 #监视k1 (当已经开始监控k1,则其他客户端不能修改k1的值)
OK
127.0.0.1:6379> set k1 2 #设置k1值为2,此操作可能由其他客户端执行
OK
127.0.0.1:6379> MULTI #开始事务
OK
127.0.0.1:6379> set k1 3 #修改k值为3
QUEUED 
127.0.0.1:6379> EXEC #提交事务,但k1值不会被修改为3,k1的值仍然是2,因为在事务开启之前k1的值被修改了
(nil)
127.0.0.1:6379> get k1
"2"

转载至:

  1. https://blog.csdn.net/ahjxhy2010/article/details/80519664
  2. https://blog.csdn.net/weixin_39561473/article/details/89287625

你可能感兴趣的:(Redis)