Redis--事务

目录

一、事务介绍

二、事务操作

[2.1 MULTI](#2.1 MULTI)

[2.2 EXEC](#2.2 EXEC)

[2.3 DISCARD](#2.3 DISCARD)

[2.4 WATCH](#2.4 WATCH)

[2.5 UNWATCH](#2.5 UNWATCH)


一、事务介绍

Redis 的事务和 MySQL 的事务概念上是类似的. 都是把一系列操作绑定成⼀组. 让这⼀组能够批量执行.
但是注意体会 Redis 的事务和 MySQL 事务的区别:
1.弱化的原子性:Redis没有"回滚机制",只能做到这些操作"批量进行"。不能做到"一个失败就回到最初状态"。
2.不保证一致性:不涉及"约束"。也没有回滚。MySQL的一致性体现的是运行事务前与运行事务后,结果都是合理有效的,不会出现中间非法状态。
3.不需要隔离性:也没有隔离级别,因为不会并发处理事务(Redis单线程处理请求)
4.不需要持久性:是保存在内存的,是否开启持久化,是redis-server自己的事情,和事务无关。
Redis事务的本质是在服务器上搞了一个"事务队列"。每次客户端在事务中进行一个操作,都会把命令先发给服务器,放到"事务队列"中(但是并不会立即执行)而是在真正受到EXEC命令之后,才真正执行队列中所有操作
因此, Redis 的事务的功能相比于 MySQL 来说, 是弱化很多的. 只能保证事务中的这几个操作是 "连续的", 不会被别的客户端 "加塞", 仅此而已.

二、事务操作

2.1 MULTI

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

复制代码
127.0.0.1:6379> MULTI
OK

2.2 EXEC

真正执行事务。

示例:

复制代码
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 的值了

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

2.3 DISCARD

放弃当前事务. 此时直接清空事务队列. 之前的操作都不会真正执行到.
示例:

复制代码
 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)

2.4 WATCH

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

复制代码
# 客⼾端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 先执行的 set key 100. 客户端2 后执行的 set key 200.
但是从实际的执行时间看, 是客户端2 先执行的, 客户端1 后执行的.

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

这个时候, 其实就容易引起歧义.
因此, 即使不保证严格的隔离性, 至少也要告诉用户, 当前的操作可能存在风险
watch命令就是用来解决这个问题的。watch在该客户端上监控一组具体的key
当开启事务的时候,如果对watch的key进行修改,就会记录下来当前key的"版本号"。(版本号是个简单的整数, 每次修改都会使版本变大. 服务器来维护每个 key 的版本号情况)
在真正提交事务的时候, 如果发现当前服务器上的 key 的版本号已经超过了事务开始时的版本号, 就会让事务执行失败. (事务中所有的操作都不执行)
示例:
客户端一先执行

复制代码
127.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

只是入队列,但不执行事务

客户端二再执行

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

客户端一再执行

复制代码
127.0.0.1:6379> EXEC # 真正执⾏修改操作, 此时对⽐版本发现, 客⼾端的 k1 的版
本号是 0, 服务器上的版本号是 1, 版本不⼀致! 说明有其他客⼾端在事务中间修改了 k1 !!! 
(nil)
127.0.0.1:6379> get k1
"200"
127.0.0.1:6379> get k2
(nil)

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

2.5 UNWATCH

取消对 key 的监控.
相当于 WATCH 的逆操作,此处不做演示

相关推荐
皙然13 分钟前
深入拆解MESI协议:从原理到实战,搞懂CPU缓存一致性的核心机制
java·缓存
晴栀ay33 分钟前
Generator + RxJS 重构 LLM 流式输出的“丝滑”架构
javascript·后端·llm
下次一定x36 分钟前
深度解析 Kratos 客户端服务发现与负载均衡:从 Dial 入口到 gRPC 全链路落地(下篇)
后端·go
彭于晏Yan2 小时前
SpringBoot整合ECC实现文件签名与验签
java·spring boot·后端
pupudawang2 小时前
Spring EL 表达式的简单介绍和使用
java·后端·spring
深蓝轨迹2 小时前
Redis 消息队列
java·数据库·redis·缓存·面试·秒杀
xianjian09122 小时前
springboot与springcloud以及springcloudalibaba版本对照
spring boot·后端·spring cloud
于樱花森上飞舞2 小时前
【Redis】初识Redis
数据库·redis·缓存
羊小猪~~2 小时前
【QT】-- QMainWindow简介
开发语言·数据库·c++·后端·qt·前端框架·求职招聘
ruxingli3 小时前
GoLang的并发如何避免死锁
开发语言·后端·golang