Redis事务相关命令:
- MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。
- EXEC:执行事务中的所有操作命令。
- DISCARD:取消事务,放弃执行事务块中的所有命令。
- WATCH:监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令。
- UNWATCH:取消WATCH对所有key的监视。
有两个客户端,都开启事务multi,然后中间发起来一系列的操作,最后两个客户端都发起exec命令,哪个先执行呢,是exec先到的先执行。
watch命令:下面是监控了 k1的,如果事务在执行前,这个k1被其他命令修改了,那么事务就被中断,不会再执行事务中的任何命令
wach k1
总结:为什么Redis不支持事务回滚?
如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。
以下是这种做法的优点:
- Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。
如下,如果事务中有几条记录,其中一条失败了,数据不会回滚。
127.0.0.1:0>mget k1 k2
1) "100"
2) "a"
127.0.0.1:0>multi
"OK"
127.0.0.1:0>incr k1
"QUEUED"
127.0.0.1:0>incr k2
"QUEUED"
127.0.0.1:0>exec
1) "101"
2) "ERR value is not an integer or out of range"
127.0.0.1:0>mget k1 k2
1) "101"
2) "a"
127.0.0.1:0>
被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。
127.0.0.1:0>watch k2
"OK"
127.0.0.1:0>multi
"OK"
127.0.0.1:0>set k1 101
"QUEUED"
127.0.0.1:0>set k2 202
"QUEUED"
127.0.0.1:0>exec
127.0.0.1:0>mget k1 k2
1) "100"
2) "123"
127.0.0.1:0>
有两个key:k1,k2,先watch k2,然后开启事务,set k1 101 set k2 202,在exec之前,我在另外一个客户端修改了 k2 = 123,当我再exec提交后,发现事务里面的操作都没有执行。