Redis(二十)-Redis的事务和锁机制

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦
💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
❤️ 2. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当 。python爬虫入门进阶
❤️ 3. Ceph实战,从原理到实战应有尽有。 Ceph实战
❤️ 4. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门
😁 5. 社区逛一逛,周周有福利,周周有惊喜。码农飞哥社区,飞跃计划
全网同名【码农飞哥】欢迎关注,个人VX: wei158556

事务

何为事务呢?我的理解是事务是一种机制,是一个不可分割的工作单元,要么都执行,要么都不执行。其具有如下四个特性:

  1. 原子性(Atomicity)
    原子性是指事务是一个不可分割的工作单元,事务中的操作要么都发生,要么都不发生。
  2. 一致性(Consistency)
    一致性是指事务前后数据的完整性必须保持一致。
  3. 隔离性(Isolation)
    隔离性是指多个事务并发执行时,一个事务的执行不应影响其他事务的执行,也就是说事务之间是相互隔离的。
  4. 持久性(Durability)
    持久性是指一个事务一旦被提交,它对数据库中的数据的改变是持久的,接下来即使数据库发生故障也不应该对其有任何影响。在关系型数据库中,事务执行完之后,执行结果就写到了硬盘中。
    上面就是事务的四个特性,简称ACID。关系型数据库事务都满足这四个特性。

Redis的事务

下面就是一个Redis事务的使用示例。
在这里插入图片描述

Redis事务的简介

Redis事务其实就是将多个命令包裹起来,一次性执行。默认是不开启事务的。Redis事务从开始到执行会经历如下三个阶段:

  1. 开始事务MULTI
    我们通过MULTI命令将执行该命令的客户端从非事务状态切换至事务状态,通过在客户端状态的flags属性中打开REDIS_MULIT标识来完成的。
127.0.0.1:6379> MULTI
OK
  1. 命令入队
    如果客户端正处于事务状态时,当添加新命令时,首先会判断这个命令是否是EXEC,DISCARD,WATCH或者MULTI这四个命令, 如果不是的话则会把命令放入事务队列中,每个Redis客户端都有自己的事务队列,它是一个multlCmd类型的数组,数组中的每个multlCmd类型的数组,数组中的每个multiCmd结构都保存了一个已入队命令的相关信息,包括指向命令实现函数的指针,命令的参数,以及参数的数量,它以先进先出(FIFO)的方式保存入队的命令,较先入队的命令会被放到数组前面,而较后入队的命令会被放在数组的后面。
127.0.0.1:6379> set name zhangsan
QUEUED
  1. 执行事务EXEC
    当一个处于事务状态的客户端向服务器发送EXEC命令时,这个EXEC命令将立即被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。
127.0.0.1:6379> exec
1) OK
2) "zhangsan"
3) OK

Redis事务的过程

在Redis事务中通过MULTI命令开启事务,输入的命令会依次进入命令队列中,此时命令并不会被执行,它相当于MySQL的事务中的Begin命令。通过exec命令执行事务,进入执行阶段,这个阶段会依次执行命令队列中的每个命令,它相当于MySQL的事务中的Commit命令。通过discard命令来放弃命令的组队,它相当于MySQL的事务中的Rollback命令。
在这里插入图片描述

事务的错误处理

如果在组队过程中某个命令报告错误,执行时整个的所有队列都会被取消。
在这里插入图片描述
演示一下:
在这里插入图片描述
如果是在执行阶段,某个命令发生了错误,那么只会影响该命令的执行,而不会影响其他命令的执行。
在这里插入图片描述
演示一下:
在这里插入图片描述

Redis事务的相关特性

Redis事务并不完全具有ACID这四种特性,它只具有一致性和隔离性。原因如下:

  1. Redis使用单线程的方式来执行事务(以及事务队列中的命令),并且服务器保证,在执行事务期间不会中断事务,因此,Redis中的事务总是以串行的方式执行,并且事务是具有隔离性的。
  2. Redis事务不过是一组包裹起来的命令,Redis并没有做特殊的持久化工作,所以一般而言Redis事务不具有持久性,Redis的持久性策略可以看上一篇文章。
  3. Redis不支持事务回滚机制(rollback),即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止,所以,Redis事务不支持原子性。如下图所示:
    在这里插入图片描述
  4. 事务总是具有一致性的。即事务执行前后数据是一致的。

Redis事务的实现原理

Redis实现事务,是基于COMMANDS队列的,也就是说,如果没有开启事务,command将会被立即执行并返回执行结果,并且直接保存在内存中,如果事务开启,command不会被立即执行,而是排入队列并返回排队状态(具体依赖于客户端(例如:spring-data-redis)自身实现),调用EXEC才会执行COMMANDS队列。

WATCH命令

WATCH命令是一个乐观锁,它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复。如下所示:
在这里插入图片描述

与MySQL事务的区别

  1. 事务的命令不同
    MySQL事务的使用如下:
BEGIN : 显式地开启一个事务
COMMIT: 提交事务
ROLLBACK: 结束用户的事务,并撤销正在进行的所有未提交的修改

而Redis事务的使用如下:

MULTI: 标记事务的开始
EXEC: 执行事务的commands 队列
DISCARD: 结束事务,并清除commands队列;
  1. 默认状态不同
    MySQL会默认开启一个事务,且缺省设置是自动提交,即每成功执行一个SQL,一个事务就会马上COMMIT,所以不能Rollback。当然,我们在同一个事务中执行多个SQL时,如果某个SQL执行失败了,则这个事务就会回滚掉。
    Redis默认不会开启事务,即command会立即执行,而不会排队,并且不支持Rollback。
  2. 实现原理不同
    MySQL实现事务,是基于UNDO/REDO日志,UNDO日志记录修改前状态,ROLLBACK命令是基于UNDO日志实现的。
    REDO记录修改后的状态,COMMIT命令是基于REDO日志实现的。
    在MySQL中无论是否开启日志,SQL都会立即执行并返回结果,只是事务开启后执行后的状态记录在REDO日志,执行COMMIT之后,数据才会被写入磁盘。

参考

《Redis设计与实现》

总结

本文简单介绍了Redis事务并将其与MySQL事务做了一下对比。Redis事务只有一致性和隔离性两种特性,不支持原子性和持久性。其实现原理是基于COMMANDS队列的,开启事务之后,命令不会被立即执行,而是排入队列并返回排队状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农飞哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值