Redis乐观锁

Redis处理事务非常简单,提供了以下几个事务相关的命令。MULTI/WATCH/EXEC/DISCARD 。更多命令请参考官方文档

Redis的事务将该链接下的所有命令放入队列中,顺序执行。当一个Session对某个Key进行监控时,不会影响到另一个Session对该Key的操作。

当提交事务时,监控Key的Session返回结果提示错误。

在终端上模拟两个Session中的交互过程。

session_1> set name session1
session_1> get name
"session1"
session_1> watch name
OK
session_1> multi
OK
session_1> set name session_01
QUEUED
session_2> set name session_02
OK
session_1> set who redis
QUEUED
session_1> exec
(nil)
session_1> get name
"session_02"
session_1> get who
(nil)
JedisPool pool = new JedisPool(/**各种参数**/);
// jedis2 与jedis1 不是同一个链接了
Jedis jedis1 = pool.getResource();
Jedis jedis2 = pool.getResource(); 
//jedis1 对 name 进行监控
jedis1.watch("name");
//从  jedis1 中获得'事物'
Transaction tx = jedis1.multi();
 tx.set("name","session_01");
//在jedis1执行后,插入 jedis2 的命令
jedis2.set("name","session_02");
//当redis1开启事物后,只能用Transaction进行修改,不能用Jedis进行修改。
tx.set("who","redis"); 
// 此时的result是null,如果没有 jedis2 对 name 的修改,结果返回["OK","OK"] 表示本次提交事物的返回结果列表。
List<Object> result = tx.exec(); 
//TODO...

在实际的项目中 name 的计算依赖于 A,B,C,D,E,F六项,而A,B,C在一个程序中,D,E,F在另一个程序中。两个程序都周期性更新A,B,C,D,E,F数据(两个程序的周期不一致)。

两个程序都需要根据自己的数据及对方的数据对 name 做计算。即第一个程序得到A,B,C后根据现有的 ‘D,E,F’ 计算出 name 的值,同样第二个程序也是如此。

所以,每个程序在计算 name 之前,需要对它进行监控(执行watch命令),然后取出另3个数据,进行计算。当提交数据时发现 name 有被修改,再尝试重新获取另3个数据,重新计算。这样可以保证数据在这个计算结果中的一致性。

之前用过Memcache+BDB,有了Redis后,应该立即放弃 Memcache+BDB方式。

本文提到的Redis版本 2.4.16

分享到: 更多