——————————————————————————————————————
Redis事务的概念
Redis的事务并不是我们传统意义上理解的事务,我们都知道单个Redis命令的执行是原子性的,但 Redis没有在事务上增加任何维持原子性的机制,所以Redis 事务的执行并不是原子性的。
事务可以理解为一个 打包的批量执行的脚本 ,但 批量指令并非原子化的操作,中间某条指令的失败不会导致前面己做指令的回滚,也不会造成后续的指令不做。
总结:
1. Redis事务中如果有某一条命令执行失败,之前的命令不会回滚,其后的命令仍然会被继续执行。 鉴于这个原因,所以说Redis的事务严格意义上来说是不具备原子性的。
2. Redis事务中所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送 来的命令请求所打断。
3. 在事务开启之前,如果客户端与服务器之间岀现通讯故障并导致网络断开,其后所有待执行的语句 都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行 EXEC 命令之后,那么该事务 中的所有命令都会被服务器执行。
Redis事务的三个阶段
-
multi开启事务
-
大量指令入队
-
exec 执行事务块内命令,截止此处一个事务已经结束。
-
discard 取消事务
-
watch监视一个或多个key,如果事务执行前key被改动,事务将打断。unwatch取消监视。
事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入 队列中排队。
Redis事务相关命令
Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH四个原语实现的
-
WATCH命令是一个乐观锁,可以为Redis事务提供check-and-set (CAS)行为。可以监控一个 或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC 命令。
-
MULTI命令用于开启一个事务,它总是返回OK。MULT I执行之后,客户端可以继续向服务器发送 任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有
队列中的命令才会被执行。
- EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排 列。当操作被打断时,返回空值nil。
通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务,并且客户端会从事务状态中退 出。
- UNWATCH命令可以取消watch对所有key的监控。
Redis事务支持隔离性吗?
Redis是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有 事务队列中的命令为止。因此,Redis事务支持隔离性。
Redis为什么不支持事务回滚?
事务具有四大特性: 1. 原子性,2. 隔离性,3. 持久性,4. 一致性。
Redis 是不支持 roll back 的,因而不满足原子性的(而且不满足持久性)。
Redis官网也解释了自己为啥不支持回滚。简单来说就是Redis开发者们觉得没必要支持回滚,这样更简单便捷并且性能更好。Redis开发者觉得即使命令执行错误也应该在开发过程中就被发现而不是生产过程中。
Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。
> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
使用 MULTI命令后可以输入多个命令。Redis不会立即执行这些命令,而是将它们放到队列,当调用了EXEC命令将执行所有命令。
你可以将Redis中的事务就理解为 :Redis事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。
Redis事务其他实现
-
基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行, 其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续 运行完。
-
基于中间标记变量,通过另外的标记变量来标识事务是否执行完成,读取数据时先读取该标记变量 判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐。