edis真是一个分布式应用场景下的好东西,对于我们的应用设计,功劳大大的!
今天要研究的是基于redis的事务机制以及watch指令(CAS)实现乐观锁的过程。
所谓乐观锁,就是利用版本号比较机制,只是在读数据的时候,将读到的数据的版本号一起读出来,当对数据的操作结束后,准备写数据的时候,再进行一次数据版本号的比较,若版本号没有变化,即认为数据是一致的,没有更改,可以直接写入,若版本号有变化,则认为数据被更新,不能写入,防止脏写。
下面,看看如何基于redis实现乐观锁。
首先,看看redis的事务,涉及到的指令,主要有multi,exec,discard。而实现乐观锁的指令,在事务基础上,主要是watch指令,以及unwatch指令,unwatch通常可以不用!
案例1:redis的纯事务
下面是ssh窗口1里面的操作:
127.0.0.1:6379> set hello 1 OK 127.0.0.1:6379> get hello "1" 127.0.0.1:6379> multi OK 127.0.0.1:6379> incr hello QUEUED 127.0.0.1:6379> incr hello #这一步执行完毕后,去另外一个窗口(ssh窗口2),对hello这个key做incr操作,将hello对应的值变成2。完成后,继续后面的exec指令 QUEUED 127.0.0.1:6379> exec 1) (integer) 3 #注意,这时hello的值是3了,前面执行get hello指令时,值是1哟,说明这个值在其他地方被修改过,这里的其他地方,就是指前面提到的,在另外一个连接窗口里面执行的。 2) (integer) 4 127.0.0.1:6379>
这个情景下,multi和exec之间的指令,依然是可以执行的。
下面的操作,就是在ssh窗口2里面的操作:
127.0.0.1:6379> 127.0.0.1:6379> get hello "1" 127.0.0.1:6379> incr hello (integer) 2 127.0.0.1:6379>
案例2: 利用watch指令,基于CAS机制,简单的乐观锁
下面是ssh窗口1里面的操作:
127.0.0.1:6379> watch hello OK 127.0.0.1:6379> get hello "4" 127.0.0.1:6379> multi OK 127.0.0.1:6379> incr hello QUEUED 127.0.0.1:6379> incr hello #这一步执行完毕后,去另外一个窗口(ssh窗口2),对hello这个key做incr操作,将其值变成5。完成后,继续后面的exec指令 QUEUED 127.0.0.1:6379> exec (nil) #注意,这是exec执行后返回的是nil,表示事务提交执行失败 127.0.0.1:6379> 127.0.0.1:6379> get hello #这个时候,查看hello对应的值,就是在另外一个窗口(ssh窗口2)执行incr后的值 "5"
下面是ssh窗口2里面的操作:
127.0.0.1:6379> incr hello (integer) 5 127.0.0.1:6379>
案例3:watch指令在一次事务执行完毕后,即结束其生命周期
下面是ssh窗口1里面的操作:
127.0.0.1:6379> multi #接着上面案例2后,不再输入watch hello这个指令,直接启动事务 OK 127.0.0.1:6379> incr hello QUEUED 127.0.0.1:6379> incr hello #这一步执行完毕后,就在另外一个窗口(ssh窗口2),执行incr hello,将hello的值变成6。 QUEUED 127.0.0.1:6379> exec #另外一个窗口(ssh窗口2)里面的操作结束后,继续来这个窗口执行该指令,依然完成了上面的两个incr hello的操作。 1) (integer) 7 2) (integer) 8 127.0.0.1:6379>
下面是ssh窗口2里面的操作:
127.0.0.1:6379> incr hello (integer) 6 127.0.0.1:6379>
上述3个案例的操作,指令其实非常的少,两个窗口的指令全集,截图如下:
在另外一个窗口(ssh窗口2)中的操作:
通过这个简单的例子,基于redis的乐观锁,可以得出一个结论:
1. 乐观锁的实现,必须基于WATCH,然后利用redis的事务。
2. WATCH生命周期,只是和事务关联的,一个事务执行完毕,相应的watch的生命周期即结束。
转载:https://www.baidu.com/link?url=lMo3SLlWGSMxGT_nv64y6EYr-p35uOr-8Vp4dtEURh7GSexKS11wLm53hZ-4Omnp9snWHPr0jAGrWU-b5LYYHa&wd=&eqid=f3667c5000056736000000055a66979c