Redis事务锁CAS实现以及深入误区

Redis中的事务

Redis的事务没有mysql那么的丰富,但在JAVA web的开发过程中利用mysql事务锁并不能满足应用场景,或者说并不是很简便,例如发放新人大礼包,代金券这种电商场景。

谈到事务,就跟acid分离不开,Redis事务也较好地满足了一致性和隔离性,但持久性和原子性一直有争议,业务上一般使用redis的组合原子操作来完成事务的原子性,redis事务的几个关键命令:

MULTI: 开启一个事务,类比于mysql的openSession
EXEC: 提交一个事务,类比于mysql的commit
DISCARD: 取消一个事务,类比于mysql的rollback
WATCH:监控一个key,与redis事务机制结合使用,形成原子锁

Redis实现CAS(Check-And-Set)的测试场景

  • 场景一:
10.185.0.120:6932> watch test
OK
// 另一个clinet 对test执行incr操作后
//在当前clinet继续操作
10.185.0.120:6932> multi
OK
10.185.0.120:6932> exec
(nil)
  • 场景二:
10.185.0.120:6932> watch test
OK
// 另一个clinet 执行下面操作
10.185.0.120:6932> multi
OK
10.185.0.120:6932> incr test
QUEUED
10.185.0.120:6932> exec
(nil)
  • 场景三:
10.185.0.120:6932> get test
"88"
10.185.0.120:6932> watch test
OK
10.185.0.120:6932> incr test
(integer) 89
10.185.0.120:6932> multi
OK
10.185.0.120:6932> incr test
QUEUED
10.185.0.120:6932> exec
(nil)
  • 场景四:
10.185.0.120:6932> get test
"89"
10.185.0.120:6932> wacth test
OK
10.185.0.120:6932> multi
OK
10.185.0.120:6932> incr test
QUEUED
10.185.0.120:6932> exec
1) (integer) 90

对上面五种场景总结:

1. client A watch,clientB set/incr等等操作,clientA 中multi-exec会失败
2. client A watch,clientB multi-set/incr-exec 也会失败
3. client A 中watch后,进行incr/set操作后,再进行multi-incr-exec 也会失败
4. client A watch-multi-incr/set-exec 成功

CAS中的误区理解

这里需要说明的是,Redis官方文档给出的watch命令的解释:

we are asking Redis to perform the transaction only if no other client modified any of the WATCHed keys

从场景三可以看出,这里的“other client” 并不一定是另外一个客户端,watch操作执行之后,multi之外任何操作都可以认为是other clinet在操作(即使仍然是在同一个客户端上操作),exec该事务也仍旧会失败

你可能感兴趣的:(Redis事务锁CAS实现以及深入误区)