Redis 13 事务
参考源
https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0
版本
本文章基于 Redis 6.2.6
概述
Redis 事务的本质是一组命令的集合
事务支持一次执行多个命令,一个事务中所有命令都会被序列化。
在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
所以说:Redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis 事务没有隔离级别的概念
批量操作在发送 EXEC
命令前被放入队列缓存,并不会被实际执行。
Redis 事务不保证原子性
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。
事务中任意命令执行失败,其余的命令仍会被执行。
Redis事务的三个阶段
开始事务
命令入队
执行事务
命令
监听
watch
watch key1 key2 ...
监视一或多个 key,如果在事务执行之前,被监视的 key 被其他命令改动,则事务被打断(类似乐观锁)。
取消监听
unwatch
取消对所有 key 的监控。
标记
multi
标记一个事务块的开始,形成队列(queued)。
执行
exec
执行所有事务块(一旦执行 exec
后,之前加的监控锁都会被取消掉)。
取消
discard
取消事务,放弃事务块中的所有命令。
实践
正常执行
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2 # 命令入队
QUEUED
127.0.0.1:6379(TX)> get k2 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k3 v3 # 命令入队
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379> get k1 # set命令执行成功
"v1"
127.0.0.1:6379> get k2 # set命令执行成功
"v2"
开启事务后,会出现 TX 标志,此时所有的操作不会马上有结果,而是形成队列(QUEUED),待执行事务后,会将所有命令按顺序执行。
放弃事务
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k3 33 # 命令入队
QUEUED
127.0.0.1:6379(TX)> discard # 取消事务
OK
127.0.0.1:6379> get k3 # set命令未执行
"v3"
事务中存在命令性错误
若在事务队列中存在命令性错误(类似于java编译性错误),则执行 exec
命令时,所有命令都不会执行。
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 11 # 命令入队
QUEUED
127.0.0.1:6379(TX)> getset k2 # 错误命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k2 22 # 命令入队
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务,报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1 # set命令未执行
"v1"
127.0.0.1:6379> get k2 # set命令未执行
"v2"
事务中存在语法性错误
若在事务队列中存在语法性错误(类似于 Java 的的运行时异常),则执行 exec
命令时,其他正确命令会被执行,错误命令抛出异常。
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k4 v4 # 命令入队
QUEUED
127.0.0.1:6379(TX)> incr k4 # 命令入队(对“v4”进行 +1 ,会报语法错误)
QUEUED
127.0.0.1:6379(TX)> set k5 v5 # 命令入队
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
2) (error) ERR value is not an integer or out of range # 执行错误的命令会报错,其余命令正常执行
3) OK
127.0.0.1:6379> get k4 # set命令执行成功
"v4"
127.0.0.1:6379> get k5 # set命令执行成功
"v5"
监听
悲观锁
悲观锁(Pessimistic Lock),顾名思义,就是很悲观。
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。
这样别人想拿到这个数据就会 block 直到它拿到锁。
传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。
乐观锁
乐观锁(Optimistic Lock),顾名思义,就是很乐观。
每次去拿数据的时候都认为别人不会修改,所以不会上锁。
但是在更新的时候会判断一下再此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量。
乐观锁策略:提交版本必须大于记录当前版本才能执行更新。
实践
初始化信用卡可用余额和欠额
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> set debt 0
OK
使用 watch 监听 balance,事务期间 balance 数据未变动,事务执行成功。
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby balance 20
QUEUED
127.0.0.1:6379(TX)> incrby debt 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
使用 watch 监听 balance,事务期间 balance 数据变动,事务执行失败。
窗口 1:
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
窗口 2:
127.0.0.1:6379> get balance
"80"
127.0.0.1:6379> set balance 200
OK
窗口 1:
127.0.0.1:6379(TX)> decrby balance 20
QUEUED
127.0.0.1:6379(TX)> incrby detb 20
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379> get balance
"200"
由于窗口 1 监听 balance 并开启事务后,窗口 2 修改了 balance 的值,导致窗口 1 的监听失败,执行事务后展示为空,且 balance 的值不是预期值。
监听失败后放弃监听,然后重来
窗口 1:
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby balance 20
QUEUED
127.0.0.1:6379(TX)> incrby debt 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 180
2) (integer) 40
小结
一旦执行
exec
开启事务后,无论事务是否执行成功,watch
对变量的监听都将被取消。当事务执行失败后,需重新执行
watch
命令对变量进行监听,并开启新的事务进行操作。watch
指令类似于乐观锁,在事务提交时,如果watch
监控的多个 key 中任何 key 的值已经被其他客户端更改。则使用
exec
执行事务时,事务队列将不会被执行,同时返回 (nil) 应答以通知调用者事务执行失败。
Redis 13 事务的更多相关文章
- Redis保证事务一致性,以及常用的数据结构
reids命令可以参考中文官网:http://redis.cn/commands.html 关于reids的使用,可以封装到工具类进行调用: Redis的工具类:JedisAdapter 除了数据结构 ...
- 第四章· Redis的事务、锁及管理命令
一.事务介绍 二.Redis乐观锁介绍 三.Redis管理命令 一.事务介绍 Redis的事务与关系型数据库中的事务区别 1)在MySQL中讲过的事务,具有A.C.I.D四个特性 Atomic(原子性 ...
- Redis的事务
Redis对事务的支持是部分支持,不想oracle,要么都成功要么都失败,Redis可以部分成功部分失败 1 是什么: 可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺 ...
- Redis笔记(五)Redis的事务
>>关系型数据库的事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消. Atomic(原子性): 一个事务(transaction)中的 ...
- redis的事务(简单介绍)
1.简单描述 redis对事务的支持目前还是比较简单.redis只能保证一个client发起的事务中的命令是可以连续的执行,而中间不会插入其他client的命令.由于redis是但现场来处理所有cli ...
- Redis的事务功能详解
Redis的事务功能详解 MULTI.EXEC.DISCARD和WATCH命令是Redis事务功能的基础.Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项: >Re ...
- Redis的事务和watch
redis的事务 严格意义来讲,redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的. redis中的事务定义 Redis中的事务(transaction)是一组命令的集合. 事务同 ...
- spring中jedis对redis的事务使用注意总结
spring的@Transactional不支持redis的事务,并且redis的事务和其它关系型数据库的事务概念不是太一样,redis事务不支持回滚,并且一条命令出错后,后面的命令还会执行. 所以不 ...
- Redis(十一):Redis的事务功能详解
相关命令 1. MULTI 用于标记事务块的开始.Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列. 这个命令的运行格式如下所示: MULTI 这个命令的返回值 ...
随机推荐
- 01C语言基础(二)
Day07 笔记 指针和函数: 栈 帧: 当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部). 当函数调用结束,这块内存区域自动 ...
- 《Unix 网络编程》11:名字和地址转换
名字和地址转换 系列文章导航:<Unix 网络编程>笔记 域名系统 简介 域名系统主要用于主机名字和 IP 地址之间的映射.主机名可以是: 简单名字,如:centos01 全限定域名(FQ ...
- sqlmap自动检测漏洞并进行渗透
使用案例靶场为上篇文章介绍的封神台---靶场 https://hack.zkaq.cn/ 提示:采用开源靶场里面的猫舍进行渗透注入,仅用于安全防范无安全侵犯 1.首先检测是否已经安装成功sqlma ...
- CabloyJS部署了一套演示站点
为了方便大家快速体验和了解CabloyJS的风格和特性,全新部署了一套演示站点.对于初次接触CabloyJS的开发者,不用下载新建项目,就可以直接体验CabloyJS了 在线演示 场景 链接/二维码 ...
- 写Selenium代码时一些技巧
本文地址: https://www.cnblogs.com/hchengmx/p/10880002.html 1. Chrome插件之"CSS Selector Helper for Chr ...
- JVM 输出 GC 日志导致 JVM 卡住,我 TM 人傻了
本系列是 我TM人傻了 系列第七期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了:https://zhuanlan.zhihu.com/p/3970425 ...
- tmux(Terminal MultipleXer)命令使用
作用:命令行多窗口显示:命令行程序与本机脱离 1 安装tmux (1)redhat.centos系统 yum install tmux (2)ubuntu系统 apt-get install tmux ...
- 自嗨ReentrantReadWriteLock
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util ...
- JAVA设计模式总结—建造者模式
建造者模式 模式动机与定义 首先建造者模式的动机是为了创建复杂对象,简化传统的创建方法,提高创建的效率和可读性. 像图中的这个例子,用户的需求是驾驶一辆汽车,但是对于用户来说是不需要了解汽车装 ...
- java基础知识面试总结-部分
前言 在平时的工作学习中,自己对微服务和springboot基础理论知识关注比较少,在面试中对于面试官的问题,很多基本都不能够达到精准,全面:现将自己面试中的问题做以总结: 1.谈谈你对微服务架构的认 ...