写在前面
本学习教程所有示例代码见GitHub:https://github.com/selfconzrr/Redis_Learning
事务特性官方文档:https://redis.io/topics/transactions
事务特性中文文档:http://www.redis.cn/topics/transactions.html
从redis2.6开始引入Redis script,将来有可能取代Redis transaction
关系型数据库的事务具备:原子性(A)、一致性(C)、隔离性(I)、持久性(D)。在Redis中也同样拥有事务的概念。
Redis事务的使用
Redis中与事务相关的命令有5个,分别是:MULTI EXEC DISCARD WATCH UNWATCH
1)MULTI命令用于开启事务:
开启事务后,可以开始对键执行操作。能看到开启事务后命令的返回都是"QUEUED",Redis Server收到这些命令后将他们保存在队列中,只有收到EXEC命令才会真正执行
2)EXEC命令:当在exec之前使用watch命令的话,只有被watch的key没有被修改的情况下,exec命令才会真正执行(类似于乐观锁optimistic lock)(案例见(4)),exec的返回结果是一个Array结构的数据,其中每个元素是事务中顺序执行的命令的结果
3)当执行了MULTI命令和一些操作后,想放弃当前事务,可以使用DISCARD命令,DISCARD命令会清空事务命令队列,并退出事务(注意discard并不是rollback回滚)。
4)WATCH命令:监控一个或者多个key,如果这些key在提交事务(EXEC)之前被其他用户修改过,那么事务将执行失败,需要重新获取最新数据重头操作(类似于乐观锁)。使得Redis事务具有check-and-set(CAS)语义,WATCH命令用法:
客户端1
客户端2
上述命令中:Client1对count使用WATCH命令后开启事务,在执行EXEC命令前,Client2修改了count的值,Client1执行EXEC命令会失败。
5)UNWATCH:取消WATCH命令对所有key的监控,所有监控锁将会被取消。
Redis事务的特性
- 单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断
- 没有隔离级别的概念:队列中的命令在事务没有被提交之前不会被实际执行
- 不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行(比如出现下面的错误类型二),没有回滚机制
在Redis事务中会出现两类错误:
- 命令语法错误、参数错误等,命令没有进入事务的命令队列,直接就返回错误。
- 命令进入事务的命令队列,但在执行EXEC后出错,例如对错误的数据类型使用了不支持的操作。
客户端可以在事务提交前就感知到第一类错误,一般客户端在收到第一类错误时会discard当前事务,当执行EXEC命令时返回:(error) EXECABORT Transaction discarded because of previous errors。比如:
在第五条命令中我随便打了几个字符,提交事务的时候并没有成功,这也很符合我们对事务的理解。从图中可以看到错误命令在我输入的时候就已经报错了,也就是说这条错误命令在进入队列的时候redis就已经知道这是一条错误命令,这样,整个事务的命令将全部失败,那么,有没有一种可能某个错误指令在进入队列的时候redis还没有发现他的错误呢?比如:
这就是我们上面提到的第二类错误,对于一个存在问题的命令,如果在入队的时候就已经知道其出错,整个事务内的命令将都不会被执行(其后续的命令依然可以入队),如果这个错误命令在入队的时候并没有报错,而是在执行的时候出错了,那么redis默认跳过这个命令执行后续命令。也就是说,redis只实现了部分事务(并不能保证事务的原子性)。
------至所有正在努力奋斗的程序猿们!加油!!
有码走遍天下 无码寸步难行
1024 - 梦想,永不止步!
爱编程 不爱Bug
爱加班 不爱黑眼圈
固执 但不偏执
疯狂 但不疯癫
生活里的菜鸟
工作中的大神
身怀宝藏,一心憧憬星辰大海
追求极致,目标始于高山之巅
一群怀揣好奇,梦想改变世界的孩子
一群追日逐浪,正在改变世界的极客
你们用最美的语言,诠释着科技的力量
你们用极速的创新,引领着时代的变迁
——乐于分享,共同进步,欢迎补充
——Any comments greatly appreciated
——诚心欢迎各位交流讨论!QQ:1138517609
——GitHub:https://github.com/selfconzrr