事务用法
Redis事务相关的命令有5个:DISCARD, EXEC, MULTI, UNWATCH, WATCH
MULTI开始一个事务,EXEC执行事务,DISCARD取消事务。在MULTI和EXEC之间的命令会得到原子的执行。Redis事务和一般数据库的事务不太相同,更像是一个原子的批处理,具体有以下两点不同:
- redis事务开始时,在EXEC之前,所有的命令都在客户端排队,并不会到服务器上执行。所以不能在事务中根据查询结果进行逻辑分支。通过稍后介绍的WATCH命令来解决。
- redis事务没有回滚,某个命令失败了继续执行下一个命令,不会恢复到事务之前的状态。
Redis事务命令如果有失败要当做BUG来处理,在开发阶段解决掉。
通过WATCH命令实现事务的逻辑分支
- 使用WATCH观察要查询的KEY(可以监控一个或多个键)
- 查询KEY得到VALUE
- 开始事务(如果决定不开始事务吗,需要使用UNWATCH取消观察)
- 根据VALUE的设定逻辑,将命令放入队列。
- 执行事务(或者DISCARD)
在第5步中如果,WATCH的值改变了,整个事务不会执行,返回一个错误,一般会从第一步开始重试(乐观锁方式)。在使用EXEC执行事务之后,会自动取消所有的WATCH,或者使用DISCARD取消事务执行,也会自动取消所有的WATCH。
除了EXEC,事务中其他的命令都不会返回失败。
事务的实现
事务开始仅仅是将客户端标记为事务状态,客户端事务状态和非事务状态的区别是:非事务状态的命令会立即发送出去,并等待返回结果;事务状态下仅仅是将命令放入队列(和事务相关的这几个命令除外)。
WATCH实现
Redis有一个watched_keys键,值是一个链表,链表中记录了所有客户端WATCH的key。所有对Redis修改的命令会去查询watched_keys,如果在被修改的key中,则将观察这个key的客户端标记(REDIS_DIRTY_CAS),说明这个客户端的事务安全性已经被破坏。在这个客户端执行事务之前,就返回错误。
事务的ACID特性
原子性,Redis事务能保证或者都执行,或者都不执行。但是不支持错误回滚。而原子性的要求是要么全成功,要么全失败,因此,Redis事务不支持原子性。
一致性,如果有入队错误,比如命令打错了,会在客户端理解返回失败,即使客户端不处理,后续的提交也会失败。如果有执行错误,如类型错误,则执行所有命令,错误被执行结果记录。
隔离性,redis是单线程的,所以事务和单个命令一样,不会互相影响。
耐久性,Redis事务的耐久性由Redis的持久化方案决定。