https://time.geekbang.org/column/article/132851

首先 Redis 不支持事务的回滚机制(Rollback),这也就意味着当事务发生了错误(只要不是语法错误),整个事务依然会继续执行下去,直到事务队列中所有命令都执行完毕。在Redis 官方文档中说明了为什么 Redis 不支持事务回滚。只有当编程语法错误的时候,Redis 命令执行才会失败。这种错误通常出现在开发环境中,而很少出现在生产环境中,没有必要开发事务回滚功能。

AOF(Append Only File)持久化采用日志的形式记录每个写操作,弥补了 RDB 在数据一致性上的不足,但是采用 AOF 模式,就意味着每条执行命令都需要写入文件中,会大大降低 Redis 的访问性能

Redis 是单线程程序,在事务执行时不会中断事务,其他客户端提交的各种操作都无法执行,因此你可以理解为 Redis 的事务处理是串行化的方式,总是具有隔离性的。。

需要说明的是 Redis 实现事务是基于 COMMAND 队列,如果 Redis 没有开启事务,那么任何的 COMMAND 都会立即执行并返回结果。如果 Redis 开启了事务,COMMAND 命令会放到队列中,并且返回排队的状态 QUEUED,只有调用 EXEC,才会执行 COMMAND 队列中的命令。

需要说明的是 MULTI 后不能再执行 WATCH 命令,否则会返回 WATCH inside MULTI is not allowed 错误(因为 WATCH 代表的就是在执行事务前观察变量是否发生了改变,如果变量改变了就不将事务打断,所以在事务执行之前,也就是 MULTI 之前,使用 WATCH)。同时,如果在执行命令过程中有语法错误,Redis 也会报错,整个事务也不会被执行,Redis 会忽略运行时发生的错误,不会影响到后面的执行。

最后我们一起思考两个问题吧。Redis 既然是单线程程序,在执行事务过程中按照顺序执行,为什么还会用 WATCH+MULTI 的方式来实现乐观锁的并发控制呢?
tt
单线程的REDIS也采用事物,我觉得主要是用来监视自己是否可以执行的条件是否得以满足,尤其是这个条件有可能不在REDIS自身的控制范围之内的时候。

作者回复: 对的,单线程不一定代表要执行的事务的条件都满足,因为其他客户端的命令可能会在WATCH之后修改了KEY的值(如文中例子),导致事务条件不满足,打断事务执行的情况。

我们在进行抢票模拟的时候,列举了两个 Redis 客户端的例子,当 WATCH 的键 ticket 发生改变的时候,事务就会被打断。这里我将客户端 2 的 SET ticket 设置为 1,也就是 ticket 的数值没有发生变化,请问此时客户端 1 和客户端 2 的执行结果是怎样的,为什么?

2、客户端2成功,客户端1失败。这个问题类似于Java并发的CAS的ABA问题。redis应该是除了看ticket的值外,每个key还有一个隐藏的类似于版本的属性。