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 这个命令的返回值 ...
随机推荐
- 博弈论(nim游戏,SG函数)
说到自己,就是个笑话.思考问题从不清晰,sg函数的问题证明方法就在眼前可却要弃掉.不过自己理解的也并不透彻,做题也不太行.耳边时不时会想起alf的:"行不行!" 基本的小概念 这里 ...
- salesforce零基础学习(一百一十五)记一个有趣的bug
本篇参考:https://help.salesforce.com/s/articleView?language=en_US&type=1&id=000319486 page layou ...
- Unicode和中午互转
import java.io.UnsupportedEncodingException; public class TestUnicode{ /* * 中文转unicode编码 */ public s ...
- Node.js安装与环境配置
废话不多少直接上干货.坐车扶稳, 当然你要知道Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台.其次Node.js是一个事件驱动I/O服务端JavaScript环境, ...
- hibernate-validator的基本使用
validator是用来校验参数使用! 一般来说校验参数的工作可以放在前端去执行,但是假如有人不经过前端直接调用后端的接口呢?很可能就出现非法数据而导致一些问题,所有服务端也要做数据的校验. 前端校验 ...
- C#项目中常见的目录和文件
本文迁移自Panda666原博客,原发布时间:2021年4月17日. Bin 目录 bin是英文binary的缩写, 字面意思是二进制,意指用来存放编译后的结果.C#/VB编译器编译后的程序二进制文件 ...
- 【Java面试】介绍下Spring IoC的工作流程
Hi,我是Mic 一个工作了4年的粉丝,在面试的时候遇到一个这样的问题. "介绍一下Spring IOC的工作流程" 他说回答得不是很好,希望我能帮他梳理一下. 关于这个问题,我们 ...
- easyui combobox重复渲染问题
当一个页面有两个easyui combobox存在时,并且同时给两个combobox赋相同值,某些easyui的版本会导致其中一个无法切换选项. 解决办法,分两步赋值,可解决问题
- js与java encodeURI 进行编码与解码
JS escape()使用转义序列替换某些字符来对字符串进行编码 JavaScript 中国 编码后 JavaScript %u4E2D%u56FD unescape()对使用 encodeUR ...
- exe4j下载和使用
https://blog.csdn.net/weixin_44678104/article/details/101015065