前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、事物

有多个命令,就会遇到事物的问题。multiexec这两个命令,一个代表事物开始,一个代表事物结束 。discard 命了可以用来放弃事务

**redis是不支持回滚的特性,只要语法没有问题,中间即使有的命令报错,其他的命令也一定会执行**

举例:社交网站上用户A关注了用户B,那么需要再用户A的关注表中添加用户B,用户B的表中添加粉丝A 这是两个操作,只能同时失败或者成功

客户端1
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd user:A:flow user:B
QUEUED
127.0.0.1:6379> sadd user:B:fans user:A
QUEUED

客户端2
这个时候,如果其他客户端执行查找命令,则会提示在队列中,不能查找成功
127.0.0.1:6379> sismember user:A:flow user:B
QUEUED
127.0.0.1:6379> smembers user:A:flow 
QUEUED
127.0.0.1:6379> 

客户端1
只有执行exec 上面两条命令才能执行成功
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> 


1.1、命令错误

1.1.1、语法命令错误不会提交事务

事物中间命令出现语法错误,事物exec不能正常执行

127.0.0.1:6379> smembers user:A:flow user:B
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> smembers user:A:flow 
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> MULTI

1.1.2、运行时错误会提交事务

当命令格式正确,而因为操作数据结构引起的错误,则该命令执行出现错误,而其之前和之后的命令都会被正常执行。就是说由于我们程序员自己的问题导致的,这样即使有事物,也不会回滚的,也都会执行,因为没有语法错误

127.0.0.1:6379> set num1 1
127.0.0.1:6379> set key healerjean
127.0.0.1:6379> set num2 2
QUEUED

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num1
QUEUED
127.0.0.1:6379> incr key
QUEUED
127.0.0.1:6379> incr num2
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (error) ERR value is not  an integer or out of range
3) (integer) 3

解决方案:针对这个问题:有些应用场景需要再执行事物之前,需要确保事物中的key没有被其他客户端修改过,才执行事物,否则不执行,Redis提供了watch命令来解决这个问题 ,作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。在执行EXEC命令之前,如果Redis检测到至少有一个键被修改了,那么整个事务便会中止运行,然后EXEC命令会返回一个nil值,提醒用户事务运行失败。

客户端1
127.0.0.1:6379> set key "healerjean"
OK
127.0.0.1:6379> watch key
OK


客户端2 
127.0.0.1:6379> multi
127.0.0.1:6379> set key "zhangyj"
OK

客户端1 (下面这个在提交的时候已经被修改了,所以执行事物的记过是nil)

127.0.0.1:6379> append key is-good-man
QUEUED
127.0.0.1:6379> exec
(nil)

ContactAuthor