前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis事务

Redis事务

作者头像
二肥是只大懒蓝猫
发布2024-07-23 08:02:25
720
发布2024-07-23 08:02:25
举报
文章被收录于专栏:热爱C嘎嘎

认识redis事务

说起事务,会不由自主地想起MySQL中的事务,MySQL中的事务有四个性质:

①原子性:把多个操作,打包成一个整体,要么全都执行成功,要么全都不执行。 ②一致性:事务执行之前和执行之后,数据能够对得上号。 ③持久性:事务中做出的修改会存在硬盘中 ④隔离性:事务并发执行,涉及到的各类读提交问题。

相较于MySQL事务,redis事务很简单:

①原子性redis原子性是指将多个操作打包在一起,要么全都执行,要么全都不执行。注意:这里跟MySQL事务中的原子性相比,redis原子性不管这些操作有没有成功,它不管!如果事务中有些操作失败了,redis说失败就失败吧。而MySQL则不行,一旦有操作失败,则全部回滚!(有部分观点任务,redis没有原子性,因为以MySQL事务的原子性作为标杆,原子性必须要么执行成功,要么不执行)

②不具备一致性:MySQL一致性是体现事务在执行前和执行后都是合理有效的,没有中间非法状态,而redis没有约束,没有回滚机制,因此事务执行过程中,某个操作失败,则可能会出现不一致的情况。

不需要隔离性:Redis是一个单线程模型的服务器程序,所有请求/事务,都是"串行"执行的

④不需要持久性:redis数据是保存在内存的.是否开启持久化,是redis-server自己的事情,和事务⽆关。

Redis事务本质就是在服务器上的一个"事务队列"(每个客户端都有一个这样的队列),客户端在事务中进行一个操作,本质就是把命令发送给服务器,放到事务队列中,但是不好立即执行,而是在主线程收到EXEC命令后,主线程才去将队列中的操作依次执行,因此,Redis事务的意义,便是:避免客户端后来的命令插队,并不会去保证执行得对不对

那么为什么redis事务,不去设计得向MySQL事务那样强大呢?

MySQL事务的强大,其背后是付出了巨大的代价的:

比如,想要实现原子性,一致性,需要实现回滚,那么需要额外开辟空间,去保存相关日志,像dolog等,再然后是每一条记录要搞个隐藏列,通过隐藏列去记录各种信息。因此空间上需要开销很大,时间上执行也有代价。redis正是因为MySQL的空间时间开销大的问题,才制定出来的。

而redis事务的场景:超卖问题。

操作事务

开启事务

MULTI

开启一个事务,执行成功返回OK。

执行事务

EXEC

真正执行事务:

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> set k3 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) OK

每次添加⼀个操作,都会提示"QUEUED",说明命令已经进⼊客户端的队列了.真正执行EXEC的时候,客户端才会真正把上述操作发送给服务器.此时就可以获取到上述key的值了。

代码语言:javascript
复制
127.0.0.1:6379> get k1
"1"
127.0.0.1:6379> get k2
"2"
127.0.0.1:6379> get k3
"3"

放弃当前事务

DISCARD

放弃当前事务,此时直接清空事务队列,之前的操作都不会去执行。

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)

监控

WATCH

在执行事务的时候,如果某个事务中修改的值,被别的客户端修改了,此时就容易出现数据不一致的问题:

代码语言:javascript
复制
# 客⼾端1 先执⾏
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 100
QUEUED
# 客⼾端2 再执⾏
127.0.0.1:6379> set key 200
OK
# 客⼾端1 最后执⾏
127.0.0.1:6379> EXEC
1) OK

此时的key是多少呢?

从输入命令的时间看,是客户端1先执⾏的setkey100.客户端2后执的setkey200.但是从实际的执行时间看,是客户端2先执⾏的,客户端1后执行的。

代码语言:javascript
复制
127.0.0.1:6379> get key
"100"

这个时候,其实就容易引起歧义.因此,即使不保证严格的隔离性,至少也要告诉用户,当前的操作可能存在风险。

watch命令就是用于解决这个问题的。watch在该客户端上监控⼀组具体的key

• 当开启事务的时候,如果对watch的key进行修改,就会记录当前key的"版本号"。(版本号是个简单的整数,每次修改都会使版本变大。服务器来维护每个key的版本号情况) • 在真正提交事务的时候,如果发现当前服务器上的key的版本号已经超过了事务开始时的版本号,就会让事务执行失败。(事务中的所有操作都不执行)

示例

客户端1先执行:

代码语言:javascript
复制
27.0.0.1:6379> watch k1 # 开始监控 k1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 100 # 进⾏修改, 从服务器获取 k1 的版本号是 0. 记录 k1 的版本
QUEUED
127.0.0.1:6379> set k2 1000
QUEUED

客户端2后执行:

代码语言:javascript
复制
127.0.0.1:6379> set k1 200 # 修改成功, 使服务器端的 k1 的版本号 0 -> 1
OK

客户端1再执行:

代码语言:javascript
复制
127.0.0.1:6379> EXEC #真正执⾏修改操作,此时对⽐版本发现,客⼾端的k1的版本不一致,返回空
(nil)
127.0.0.1:6379> get k1
"200"
127.0.0.1:6379> get k2
(nil)

此时说明事务已经被取消了.这次提交的所有命令都没有执行。

UNWATCH--取消监控。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 认识redis事务
  • 操作事务
    • 开启事务
      • 执行事务
        • 放弃当前事务
          • 监控
            • 示例
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档