• 实战详解Redis事务


    1 缘起

    Redis是数据库,
    自然会想到,这个数据库是否有事务这个概念?
    当然有。我也是通过学习Redis才发现这个概念的,
    于是开始查看相关文档
    发现,Redis的事务与常说的关系型数据库的事务有所不同,
    现结合实践整理成文,帮助读者通过实践的方式理解Redis事务
    轻松应对知识考核与交流。

    2 事务

    Redis事务支持命令拆解单步执行,通过MULTI、EXEC、DISCARD和WATCH这些命令将原始的命令拆解为单步执行的命令。Redis事务保证:

    • 事务中的命令是序列化且顺序执行的。执行中的事务不会对另外的一个客户端提供服务,即隔离性。
    • EXEC命令触发事务中所有的子命令执行,如果某个客户端在调用EXEC前与服务端断开连接,所有的子命令都不会执行。使用append-only文件时,Redis确保使用单写入(2)系统调用将事务写入磁盘。如果Redis服务端冲突或被系统管理员kill掉,此时仅注册部分操作。Redis会在重启时检测这些情况,此时Redis服务端因错误而退出系统。可使用redis-check-aof工具修复(移除记录的部分事务),以启动Redis服务。

    3 应用

    3.1 事务执行过程

    Redis的事务执行过程如下图所示,
    由图可知,通过MULTI命令开启事务,
    开启事务后,开始执行相关的命令,这些命令操作会记录(缓存)到队列中,
    使用EXEC命令执行当前事务队列中存储的命令。
    在这里插入图片描述
    实际验证一下,测试过程如下图所示,
    由图可知,MULTI开启事务后,之后的操作命令都会进入当前事务的队列,
    入队后,返回QUEUED,表明正常入队,
    当,完成事务准备后,通过EXEC命令,提交事务,即处理当前事务中的命令,
    EXEC命令返回执行的命令个数,OK标识执行成功。
    在这里插入图片描述

    3.2 事务取消过程

    Redis取消事务通过DISCARD命令,
    执行过程如下图所示,
    由图可知,通过MULTI命令开启事务后,
    向事务队列写入指令,
    如果想取消当前事务,使用DISCARD命令。
    在这里插入图片描述

    取消事务验证过程如下图所示,
    由图可知,执行DISCARD命令后,直接返回OK,表明已经取消事务,
    再次查询数据时,仍是取消事务前的数据,
    当前的事务没有生效。
    在这里插入图片描述

    3.3 不支持事务原子性

    按照关系型数据库的事务逻辑,
    原子性是一荣俱荣,一损俱损,
    当事务中任意一个步骤出问题,当前步骤中所有步骤均不生效,
    但是,Redis不属于关系型数据库,并且,Redis秉承简洁、高效的传统,
    Redis的事务并不能保证严格的原子性。
    Redis的事务目前仅支持将执行任务拆分,并不支持严格的原子性。
    验证Redis的非严格原子性过程如下图所示,
    由图可知,使用MULTI开启事务后,所有的操作命令(非EXEC,DISCARD)只是被存储到队列,
    并没有执行和校验,为什么这么讲?因为,sex是字符型kv对,使用incr命令时,只提示QUEUED,入队成功,
    并没有提示错误,
    当使用EXEC命令后,发现第二条命令执行异常,
    第一条和第三条命令执行正常,
    所以,Redis的事务不支持严格原子性,
    该失败的失败,该成功的成功,互补干扰。
    以查询结果为证,name值已经成功修改,sex未被成功修改,维持原值。

    在这里插入图片描述

    3.4 隔离性

    通过上面的测试,name的值被修改为xiaoxiao,
    现在测试Redis事务的隔离性,
    即客户端A开启的事务提交前,其他客户端无法读取到当前事务中进行的变更,
    测试结果如下图所示,
    由图可知,新开启的客户端读取到的数据为稳定的数据,
    这样保证了事务修改数据期间,不会造成脏数据,但是,并发问题不能解决,下文讲。

    在这里插入图片描述

    3.5 并发

    客户端A开启事务,客户端B开启事务,
    时间线如下图所示,
    由图可知,客户端A和B在不同的时间执行EXEC和查询数据,
    事务之间没有锁,索引,谁先执行EXEC谁先生效,
    导致,并发时,事务是不安全的。

    在这里插入图片描述
    时间n和时间n+1的执行过程如下图所示,
    由图可知,客户端B的先执行EXEC,因此,此时的name为客户端B生效的值:xiaxosan。
    在这里插入图片描述
    时间n+2和时间n+3执行过程如下图所示,
    由图可知,客户端A执行EXEC后,获取的值为客户端A生效的值:xiaoer。
    由此可知,并发时,Redis仅使用MULTI和EXEC无法保证数据安全更新。
    在这里插入图片描述

    3.6 并发监控机制

    为保证并发时事务的安全性,通过WATCH命令来给具体的键添加监控,即更新锁,
    WATCH的使用规则如下图所示,
    由图可知,WATCH是在开启事务前执行的,
    用于约定监控哪些key,当监控的Key在当前事务执行前被其他事务修改,则不进行当前事务的变更,
    执行为nil(不操作),保证并发的安全。

    在这里插入图片描述
    测试流程如下图所示,测试流程是按照下图的标号顺序进行的。
    客户端A开启事务前监控name,然后,开启事务,
    客户端B直接开启事务,直接修改name,提交,成功执行,
    客户端A再执行EXEC时,发现,返回nil,表明键name已被其他事务修改,本事务不进行操作,
    WATCH监控,保证了并发时修改键的安全性。

    在这里插入图片描述

    4 小结

    (1)Redis有事务概念,Redis支持将命令拆分为单步事务执行;
    (2)Redis不支持原子性,无法回滚;
    (3)Redis支持事务隔离性,保证不会读到未提交的脏数据;
    (4)并发时,使用WATCH监控键,保证数据安全更新。

  • 相关阅读:
    数据治理之springboot项目入门
    匈牙利算法 求二分图最大匹配
    中秋海报制作不求人,详细教程来袭
    FVM管理Flutter 环境
    Spring Boot+Vue3前后端分离实战wiki知识库系统之分类管理功能开发
    Spring MVC 入门指南
    J2EE基础-通用分页(2)
    软件依赖管理-源码依赖、接口依赖、服务依赖
    数据库-玩转数据-Pgsql 使用UUID做主键
    verilog--用于电路设计--0
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/126786498