Redis核心技术---事务管理

版权声明:转载注明出处 https://blog.csdn.net/czr11616/article/details/84065395

目录

1.Redis事务基本命令

2.开启与执行事务

3.事务回滚

4.多线程中的事务


1.Redis事务基本命令


虽然redis是一种基于内存的nosql,但是其也是支持事务的,只不过没有传统的关系型数据库(如MySql)那么强大,下面给出redis的事务命令:

表1-1     Redis事务命令
命令 说明 备注
multi

开启事务命令,之后的命令就进入队列,而不会马上被执行

在事务生存期间,所有的Redis关于数据结构的命令都会入队
watch key1[key2....] 监听某些键,当被监听的键在事务执行前被修改,则事务会被回滚
unwatch key1[key2...] 取消监听某些建

exec 执行事务,如果被监听的键没有被修改,则采用执行命令,否则就回滚命令 在执行事务队列存储的命令前,Redis会检测被监听的键值对有没有发生变化,如果没有就执行命令,否则就回滚事务
discard 回滚事务 回滚进入队列的事务命令,之后就不能再用exec命令提交了。

2.开启与执行事务


 redis通过multi开启事务,事务开启后的所有命令都会放入队列中等待执行,当遇到exec命令时,将会一次性执行队列中的所有命令,如下图测试:

 从上图可以发现,使用multi命令开启事务后,接下来的set命令和get命令按回车执行后都会显示QUEUED,表示该命令已经放入队列,当执行exec命令的时候,队列中的所有命令将会一次性全部执行,并返回执行结果,如上图所示返回OK和“value1”。

3.事务回滚


如表1-1,事务回滚的命令为discard,关于事务回滚这里有三种情况,分别为

手动执行discard命令进行回滚、遇到命令格式错误redis自动进行回滚、遇到操作数据错误(如数据格式错误)不回滚

1. 在开启的事务被执行(exec)前,如果执行事务回滚命令(discard),则之前放入队列中的所有命令将会被清除,此时如果再执行exec会报错,因为队列中已经没有了命令,如下测试结果:

2.在开启事务后如果执行的命令格式错误(注意是格式错误),则Redis会自动回滚exec前的所有命令。如下:

如上,在输入了错误的命令ged key1后,执行exec命令会提示:Transaction discarded because of previous errors,表明事务已经被回滚了,此时exec之前的所有命令都不会被执行(注意在Redis2.6.5之前的版本会忽略有语法错误的命令,然后执行事务中其他语法正确的命令)

3.那如果命令格式没有错,但是运行错误(数据格式错误或者用操作链表类型的命令操作集合类型)呢?Redis会怎么回滚呢?如下:

如上图,incr key1命令本身没有错,但是由于key1的值是字符串而不是整数,不能对其使用incr(自增)运算,所以exec后会报错,但是读者会发现出错的命令之前和之后的命令都被正常执行了,由此可以看出由于数据格式导致的错误Redis事务并不会被正确回滚。

那么到这里读者可能会有疑问了,那要怎么解决呢?答案是解决不了啊哈哈哈哈,redis并不支持回滚运行错误的事务,我们必须通过程序去检测数据的正确性,以保证Redis事务的正确执行,如果万一事务提交时出现了运行错误,那么我们只好自己收拾剩下的摊子了(即将数据恢复事务执行前的状态)。

那我们可爱的读者可能又会有疑问了,为什么Redis不支持呢?是因为实现不了吗(怎么可能哈哈哈哈哈),要知道安全和性能从来都是鱼和熊掌的关系,Redis为了保持其性能只能削弱其事务管理的功能啦。

4.多线程中的事务


我们之前讨论的情况都是在单线程的环境中,当存在多线程时又是另外一种情况了。

当A线程去执行某些业务逻辑,而这些业务逻辑所操作的数据(公共数据)又被B线程共享了,B线程很有可能会去修改公共数据,而A线程并不知道数据被修改了,最终导致的后果就是A线程的业务逻辑运算很有可能出错。

那么怎么解决呢?我们可以对公共数据加一个检测其是否被改变的监听器,那就是我们表1-1中的watch命令啦。当redis使用exec命令执行事务的时候,他首先会去对比被watch命令所监控的键值对,如果没有发生变化,那么他会执行事务队列中的命令,提交事务,如果发生变化,那么它不会执行任何事务中的命令,而去回滚事务。无论事务是否回滚,redis都会去取消执行事务前的watch命令。

由于多线程示例不好实现,我们以表格的形式向读者举例说明watch命令的使用:

表1-4   watch命令在多线程中的使用
时刻 线程1 线程2 说明
T1 set key1 value1 ----- 线程1:创建了一条共享数据key1
T2 watch key1 ----- 线程1:开启了对共享数据key1的监控
T3 multi ----- 线程1:开启了事务
T4 do something ....... ----- 线程1:在事务中执行了一些逻辑操作
T5 ------ set key1 newValue1 线程2:修改了公共数据key1的值
T6 exec ----- 线程1:线程一在提交事务时,会去检测在T2时刻被监控的公共数据key1是否被修改过,发现key1在T5时刻被线程2修改了,所以线程1会直接回滚事务,multi到exec之间的命令都不会被执行。

 

猜你喜欢

转载自blog.csdn.net/czr11616/article/details/84065395
今日推荐