Redis事务介绍
Redis的事务是一组命令的集合,将多个命令打包,然后这些命令会【按照顺序(FIFO)】被添加到【执行队列】中,最后按照顺序执行。
Redis事务没有像 MYSQL 关系型数据库事务隔离级别的概念,他不能保证原子性操作,为什么呢?
其实这和 Redis 自身的特点有关,Redis 是快速高效的,而回滚操作、像事务隔离级别那样加锁、释放锁,是非常消耗性能的,这与 Redis 的特点相悖。
如果 Redis 的事务也像关系型数据库的事务那么稳定,它就不会这么高效了,毕竟,鱼和熊掌不能兼得嘛~
所以 Redis 执行事务非常简单,只需要3个步骤:
1.开始事务 MULTI
2.命令入队(FIFO)
3.执行事务EXEC,撤销事务DISCARD
Redis事务中的一些命令:
—MULTI:开启事务,操作命令会按照顺序放入队列中,执行EXEC命令后被执行
—DISCARD:抛弃执行队列中的命令,可以理解成MYSQL的回滚操作,并将状态由“事务状态” 改为 “非事务状态”
—EXEC:按照顺序执行队列中的命令
—WATCH:监听key,如果监听到key被其他客户端修改了,那么EXEC就会放弃执行队列中的所有命令,直接向客户端返回nil表示事务执行失败(类似乐观锁机制)
—UNWATCH:取消监视
Redis事务的缺陷
Redis事务不支持原子性,也不支持持久性
这里可能会有疑问,Redis 不是有持久化机制吗?为什么不支持持久性?
确实有持久化机制,但我在之前的文章中也谈到,Redis 持久化机制的设计初衷是为了数据恢复,它不能实现像关系型数据库那样的实时持久化。
—比如RDB持久化,它是以快照的方式记录某一时刻的内存数据,而且是全量快照,记录内存中的所有数据。这个量级是比较大的,所以执行频率不能太高,否则就会影响性能。既然执行频率不高,那么肯定就会有数据丢失的风险。
—AOF日志,记录的是每一条写命令,相比RDB,这种持久化方式的实时性比较好。它的刷盘策略有3种:Always、No、EverySec,No和EverySec这两种策略都会存在数据丢失,always基本可以满足持久性,但是性能太差,在实际开发中也不会使用。
综上,Redis 事务无法保证持久性。
弥补缺陷
Redis 从2.6版本开始支持 lua 脚本,利用 lua 脚本来批量执行多条 Redis 命令,这些命令会被提交到 Redis 服务器一次性执行,大大减少了网络开销。
但是,如果 lua 脚本在运行时出错并且中途结束,出错之后的命令不会被执行,出错之前的命令无法被撤销,所以严格来说,通过lua脚本批量执行 Redis 命令也不能完全满足原子性。