Redis事务系列之一Redis事务详解
Posted 程序编织梦想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis事务系列之一Redis事务详解相关的知识,希望对你有一定的参考价值。
一、前言
本章是redis事务系列知识第一章,redis事务系列主要讲解以下内容:
redis 事务
redis乐观锁讲解
redis乐观锁实现秒杀
我们一步一步来,本章主要讲解事务。
二、事务
2.1事务阐述
讲redis事务之前,我们先来看看事务的定义。
事务:一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
但redis的事务不并不是完整意义上的事务,我们称之为弱事务,为什么这么说呢?
redis中并没有回滚这种机制,也就是说,在一个事务中,中间一条命令执行失败,并不会导致前面已经执行的指令回滚。也不会造成后续的指令不做。我会在下面画图验证不支持回滚。
2.2 事务命令讲解
事务的命令一共就五条,为了方便大家记忆,我们先记住下面三条命令,:
1.开启事务:MULTI
2.执行事务:EXEC
3.取消事务:DISCARD
就像mysql中用begin开启事务、用commit结束事务一样。redis中是用multi开启事务,用exec执行命令。如果在exec之前你不想执行事务了,可以用discard取消当前事务。下面我们举例说明:
开启事务和执行事务的例子
> multi //开启事务
> set s1 aaa
> set s2 bbb
> exec //执行事务
> get s1 // 获取s1的值
"aaa"
> get s2 // 获取s2的值
"bbb"
开启事务和取消事务的例子
> multi //开启事务
> set s3 222
> discard //结束事务
OK
> exec //因为事务已经在上面取消了,所以在这里执行事务会报错。
(error) ERR EXEC without MULTI
> get s3 //事务被取消了,所以这里s3根本就没有值
(nil)
2.3 事务为什么不支持回滚
讲解“事务为什么不支持回滚”之前我们先来汇总一下redis事务执行异常的几种情况,然后再总结事务为什么不支持回滚。
1.语法错误导致事务执行异常,该事务取消
在开启事务后,修改h1值为11111,h2值为2222,但h2语法错误,最终导致事务提交失败,h1、h2保留原值。
> set h1 11
> set h2 22
> multi //开启事务
> set h1 11111
> sets h2 2222 // 语法错误,下面报错
(error) ERR unknown command `sets`, with args beginning with: `h2`, `2222`,
127.0.0.1:6379> exec //执行事务,因为前面有语法错误,所以此事务取消
(error) EXECABORT Transaction discarded because of previous errors.
> get h1 // h1和h2的值并没有在事务中改变
"11"
> get h2
"22"
2.运行时错误(Redis类型错误)导致事务异常
在开启事务后,修改s1值为1111111,s2值为2222222,但将s2的类型作为List,在运行时检测类型错误,最终导致事务提交失败,此时事务并没有回滚,而是跳过错误命令继续执行, 结果s1值改变、s2保留原值。
> set s1 11
> set s2 22
> multi
> set s1 1111111
> lpush s2 2222222 //此处类型错误,s2的类型是字符传,但我们把S2的类型作为List提交
> exec //提交执行事务报错。
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
> get s1 //s1的值修改成功
"1111111"
> get s2 //s1的值修改失败
"22"
总结:为什么Redis不支持事务回滚?
以上两个例子总结出,多数事务失败是由语法错误或者数据结构类型错误导致的,语法错误说明在命令入队前就进行检测的,而类型错误是在执行时检测的,Redis为提升性能而采用这种简单的事务,这是不同于关系型数据库的,特别要注意区分。
2.4 watch和unwatch命令讲解
2.4.1 watch命令
上面我们讲到redis是的事务是不支持回滚的,但是我们一定要让它回滚怎么办呢?这就需要用的watch命令了。
watch使用要注意:watch在mutil命令之前使用.
watch的作用是:监控一个值是否发生变化,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。最后无论是否回滚,Redis都会取消执行事务前的WATCH命令。
这么说不太好理解,我们画图表示一下:
下面我们用代码验证一下,场景如下:
在事务开始前用WATCH监控a1,之后修改a1为c1111,MULTI开始事务,修改a2为c2222,执行EXEC,返回nil,说明事务回滚;查看下a2的值都没有被事务中的命令所改变。
代码如下:
//先设置2个值,我们用监控a1,然后用a2判断是否发生的回滚。
127.0.0.1:6379> set a1 1111
127.0.0.1:6379> set a2 2222
127.0.0.1:6379> watch a1 //监听a1
127.0.0.1:6379> set a1 c1111 // a1的值在监控后发生了改变。
127.0.0.1:6379> multi //开始事务
127.0.0.1:6379> set a2 c2222 //设置a2的值
127.0.0.1:6379> exec //执行事务,发生错误,事务回滚
(nil)
127.0.0.1:6379> get a2 //a2的值并没有被更改,依旧是2222
"2222"
2.4.2 unwatch命令
unwatch命令是取消监控,这里就不过多介绍了,下面是代码:
> set k1 1111
> set k2 2222
> WATCH k1
> set k1 11 //改变k1的值
> UNWATCH //取消监控
> MULTI //开启事务
> set k1 12
> set k2 22
> exec //执行事务成功了
1) OK
2) OK
> get k1
"12"
> get k2
"22"
三、结尾
好了,就讲到这里吧,这一章虽然知识点不多,但是小编为了更加通俗地讲出来也想了2、3天。
码字不易,希望大家关注一下小编,感谢!
另外,大家帮忙关注一下我微信公众号,感谢!关注后我有上百套学习资料和视频课程赠送。
以上是关于Redis事务系列之一Redis事务详解的主要内容,如果未能解决你的问题,请参考以下文章