Redis高级篇
-
事务
MULTI, EXEC, DISCARD and WATCH命令用于保证Redis中的事务处理
一个事务中的所有命令被序列化并串行执行。
事务的原子性。
用法
MULTI 进入一个事务,这个命令响应“OK”。
EXEC开始执行事务中的命令。
DISCARD将退出事务。
> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
事务错误处理
事务执行可能出现两种错误:
- 在EXEC执行前,命令不能正常添加到Queue中。例如,命令出现语法错误等。
- 在EXEC执行后,例如在string类型上进行list操作。
针对于第一种错误,Client通常能看到,在执行命令后响应为“QUEUED”说明成功,否则失败。
为什么Redis不支持事务回滚
如果你有使用过关系式数据库的经验,那么“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪 。
原因如下:
- Redis 命令只会因为错误的语法而失败(这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
有种观点认为 Redis 处理事务的做法会产生 bug ,然而需要注意的是,在通常情况下,回滚并不能解决编程错误带来的问题。举个例子,如果你本来想通过INCR 命令将键的值加上 1 ,却不小心加上了 2 ,又或者对错误类型的键执行了INCR,回滚是没有办法处理这些情况的鉴于没有任何机制能避免程序员自己造成的错误,并且这类错误通常不会在生产环境中出现,所以 Redis 选择了更简单、更快速的无回滚方式来处理事务
Discarding the command queue
DISCARD用来中止事务。
> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"
用check-and-set(CAS)优化锁
WATCH命令用来监控更新事务的状态。。
WATCH 关键字用来监控为了keys的变化。在EXEC执行前,如果监控中的任一key发生变化,那么事务将会停止,并且EXEC将返回空表示事务失败。例如,我们需要使key自增1(假设Redis没有INCR),做法如下:
val = GET mykey
val = val + 1
SET mykey $val
这种做法对于单个client没有问题,可是对于多个client同时进行操作的话,那么就有问题了。通过WATCH命令我们就能很好地解决这个问题:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
上面的代码中,如果其它client修改了WATCH和EXEC之间的变量val,那么事务将会失败。
WATCH
WATCH可理解为有条件的EXEC命令,也就是说如果要执行事务,那么必须是WATCHed的keys都没有被其它client修改过,否则事务不执行。
WATCH能被多次调用。
使用UNWATCH(无参数)命令移除不需要监控的keys。
使用WATCH实现ZPOP命令(原子型操作:从集合中移除score最低的元素)的功能
WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC