你见过不长毛的羊吗

Redis(八)-事务

2019.08.08

1. Redis事务是什么

  • 一次执行多个命令,本质是一组命令的集合。事务中的所有命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断

2. 事务相关的命令

  • watch key [key...]:监视一个或多个key。如果在事务执行之前这个或这些key被其他命令锁改动,那么事务会被打断

  • multi:标记一个事务块的开始

  • exec:执行所有事务块内的命令

  • discard:取消事务,放弃执行事务块内的所有命令

  • unwatch:取消watch命令对所有key的监视

3. 事务案例演示

  1. 正常执行
multi				# 开启事务
set k1 v1				# 入队
set k2 v2				# 入队
get k2				# 入队
set k3 v3				# 入队
....					# 入队
exec				# 执行事务
  1. 放弃事务
multi				# 开启事务
set k1 v1				# 入队
set k2 v2				# 入队
get k2				# 入队
set k3 v3				# 入队
....					# 入队
discard				# 放弃事务
  1. 命令语句错误(全体连坐)
multi
set k1 v1
set k2 v2 
get k2
get set excprisks  # 这里会入队错误
set k5 v5
...
exec

此时get set excprisks加入队列报错,导致当前事务中全部语句不能被执行

  1. 执行时出错(冤头债主)
multi
set k1 v1
incr k1  # 此时v1为非数字,执行时会出错
set k2 v2
get k2
...
exec
此时<code>incr k1 </code>加入队列成功,只是执行的时候会报错。但是其他命令都会成功执行

由第3、4点得出:Redis的事务是部分支持

4. watch监控

  • 注意:一定是先监控,再开启事务

  • 案例

    • 说明:此时Redis库中已有值balance-100、debt-0
    	watch balance          #  此时balance为100,debt为0
    	 # 假设,这里有其他客户端A将balance修改为200
    	multi
    	decrby balance 20
    	incrby debt 20
    	exec
    

    本次事务执行失败。因为在事务执行之前balance数据已经不是watch时的值。此时,获取到的balance为200。

    如果watch后,数据被人改了,执行unwatch命令,取消对所有key的watch。然后再重新watch,再执行事务。

  • 总结 watch 类似乐观锁,事务提交时,如果key的值被其他客户端修改了,整个事务队列不会执行。 通过watch命令在事务之前监控了多个keys,如若在watch之后有任何被监视的key的值发生了变化,exec命令执行的事务都会被放弃,并返回Nullmulti-bulk告诉调用这事务执行失败。

5. Redis事务总结

  • 单独的隔离操作 事务中所有命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念 队列中的命令没有提交之前都不会实际的被执行,也就不存在事务内的查询要看到事务里的更新。
  • 不保证原子性 redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。