自学内容网 自学内容网

Redis:事务


事务

MySQL中,事务遵循CIRD特性:

  1. 原子性:事务是一个整体,要么没有发生,要么已经执行完毕
  2. 一致性:事务执行前后,数据都要符合业务要求
  3. 隔离性:事务并发时,各个事务之间的可见性受到一定限制
  4. 持久性:事务做出的修改会被存储到硬盘中持久化

由于MySQL是支持并发的,所以MySQL的事务机制非常复杂,要考虑很多情况。但是Redis不同,作为一个单线程模型的数据库,Redis根本就没有并发问题,所以Redis的事务机制会简单很多。

Redis的事务特点如下:

  • 弱化原子性:在Redis中,没有回滚机制,不能做到事务中一个命令出错,回滚到事务开始前,简单理解来说,Redis的事务就是一个简单的打包执行
  • 无需隔离性:由于Redis是单线程模型,不会出现并发,不会有多个事务同时进行,所以不需要隔离性
  • 无需持久性Redis是内存级别的数据库,虽然有持久化机制,但是事务执行完毕后,不能保证数据被写入硬盘
  • 不保证一致性:在MySQL中,一致性是通过前三个特性都满足进而达成的,很不巧Redis都不满足,自然也就不能保证一致性了

既然如此,Redis的事务有啥用?

其实Redis的事务就像一个简单的打包,保证一个事务内部的指令是连续执行的。就像在排队时,几个好朋友总要连着站在一起,不让别人插在中间。

假设排队的时候,先到了几个人,还有几个人没来,此时如果占着排队的位置,让后来的朋友直接插入,貌似有点不道德了。所以一种处理策略是,在朋友到来之前,让后面的人排到前面去,等到朋友来了,几个人再一起插入队尾。

也就是说,Redis的事务策略,不是先抢占位置,而是先空出位置给别的事务,等到自己一个事务内部的所有操作都齐全了,再一起执行。


事务操作

MULTI & EXEC

  • multi:开启事务
  • exec:提交事务

示例:

在这里插入图片描述

开启事务后,不论输入什么指令,都返回QUEUE,此时会在客户端维护一个队列,将所有指令入队列。最后执行exec提交事务,所有的指令再同时返回。


DISCARD

  • discard:取消事务

示例:

在这里插入图片描述

开启事务后,输入两个值,再通过discard取消事务,最后查询key1,发现插入失败,因为这个请求没有提交给客户端,而是直接被取消了。

另外的,如果在事务执行的过程中,Redis崩溃,恢复后效果和discard一样,就是事务内的操作都取消了。


WATCH

现有以下场景:

序号客户端1客户端2
1multi
2set key 111
3set key 222
4exec
5get key

最后客户端get key返回值是多少?

这是一个很常见的事务问题,虽然客户端1执行set key更早,但是它提交事务更晚,最终客户端的结果其实是111

在这里插入图片描述

在事务执行过程中,客户端1无法感知外部的变化,导致客户端2拿不到自己想要的数据,被其他事务覆盖了。

  • watch:让事务可以监听外部的变化,如果监听的数据被外部改变,操作失效

语法:

watch key [key ...]

示例:

在这里插入图片描述

左侧的终端,在执行事务前开启了watch key1,开启事务后set key1 111。在事务提交前,右侧终端修改了key1 222,随后左侧终端提交事务时,返回了nil表示事务操作无效。

因为watch监听到了key1被外部修改,此时自己的事务提交可能会影响其它客户端,于是取消该操作。

如果想要取消watch,可以使用unwatch指令:

unwatch

这个指令没有参数,一次性取消所有key的监听。

watch使用了一种版本号的机制,每个数据都有一个版本号,每次修改key的值时,都会修改其版本号。在watch key时,会记录当前的版本号。在事务提交时,检测当前的版本号是否与之前的版本号相同,如果相同那么提交成功,如果版本号不同,说明有别的用户修改了数据,导致版本号修改,事务就直接被丢弃了。



原文地址:https://blog.csdn.net/fsdfafsdsd/article/details/142766942

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!