引入Redis事务的现实需求:redis 的单个命令都是原子,比如set get,但是多个redis命令如何做到原子性呢?
答案是两种实现方式:要么是Redis事务,要么是Lua脚本。
Redis事务特性
1、按进入队列的顺序执行,先进入先执行
2、不会受到其他客户端的请求的影响
3、事务不能嵌套,多个multi命令效果一样
事务命令:
multi:开启事务,multi表示多条,就是开启事务的意思
exec:执行事务
discard:取消事务/回滚事务
watch:监视key,如果被监视的key在exec之前被修改,事务会取消(凡是进入到事务里面就被watch了,只有修改,事务队列里这个就不能执行成功)
watch 命令的底层原理类似 cas 乐观锁(compare and set),为什么是乐观锁呢?其实还是为了保证 redis 的速度
set tom 1000
set mic 1000
multi
decrby tom 100
incrby mic 100
exec
get tom
get mic

事务的取消和watch
discard:取消事务
watch:监视key,如果被监视的key在exec之前被修改,事务会取消(凡是进入到事务里面就被watch了,只有修改,事务队列里这个就不能执行成功)
watch 命令的底层原理类似 cas 乐观锁(compare and set),为什么是乐观锁呢?其实还是为了保证 redis 的速度
事务发生异常包括两种:执行事务之前 + 执行事务之后
如果执行exec事务之前出现错误,可以回滚
如果执行exec事务之后出现错误,不可以回滚
对于执行exec事务之后出现错误,Redis的设计不可以回滚,这样设计的理由是:
(1) 一般来说,执行exec事务之后发生的都是语法错误,这种错误如果已经在测试环境中执行了,在生产环境中不会犯这样的错误;
(2) 如果向 mysql 一样,提供一个 undo log 日志,会对redis速度产生影响。
Redis 为了性能考虑,不做 undolog 日志,就无法回滚执行 exec事务 之后的错误,这也是 Redis 事务的局限性,所以开发中解决多个redis命令的原子性问题,基本都会才有 lua脚本 实现,而不是 Redis 事务。
Redis事务,完成了。