李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
Redis事务简介
Leefs
2020-03-20 PM
1179℃
0条
# Redis事务简介 ### 一、Redis事务是什么? **可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入** Redis对事务的支持是部分支持 ### 二、作用 一个队列中,一次性、顺序性、排他性的执行一系列命令 ### 三、Redis事务命令 | 命令 | 描述 | | -------------------- | ------------------------------------------------------------ | | DISCARD | 取消事务,放弃执行事务块内的所有命令 | | EXEC | 执行所有事务块内的命令 | | MULTI | 标记一个事务块的开始 | | UNWATCH | 取消WATCH命令对所有key的监视 | | WATCH key[key......] | 监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。 | ### 四、案例说明 **正常执行:** 先通过multi命令进行开始事务,然后执行输入的命令,在输入exec结束事务命令后,在此中间输入的命令都正常一起执行输出。 ```java 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) "v2" 4) OK ``` **放弃事务:** ```java 127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> set k3 33 QUEUED 127.0.0.1:6379> discard OK 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> ``` **全体连坐:** 在开启事务输入要执行的语句之后,只要有一个命令错误(不符合Redis命令格式直接报错),该事务内的所有命令执行失败 ```java 127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 11 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> setget k3 (error) ERR unknown command 'setget' 127.0.0.1:6379> set k5 v5 QUEUED 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k5 (nil) ``` **冤头债主:** Redis内部数据格式错误时候会出现冤头债主。 ```java 127.0.0.1:6379> multi OK 127.0.0.1:6379> incr k1 QUEUED 127.0.0.1:6379> set k2 22 QUEUED 127.0.0.1:6379> set k3 33 QUEUED 127.0.0.1:6379> get k3 QUEUED 127.0.0.1:6379> exec 1) (error) ERR value is not an integer or out of range 2) OK 3) OK 4) "33" ``` **watch监控:** 悲观锁/乐观锁/CAS(Check And Set) **悲观锁**:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁 **乐观锁:**顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量 **乐观锁策略:**提交版本必须大于记录当前版本才能执行更新 示例: 初始化 ```java 127.0.0.1:6379> set balance 100 OK 127.0.0.1:6379> set debt 0 OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> decrby balance 30 QUEUED 127.0.0.1:6379> incrby debt 30 QUEUED 127.0.0.1:6379> exec 1) (integer) 70 2) (integer) 30 127.0.0.1:6379> get balance "70" 127.0.0.1:6379> get debt "30" ``` **正常执行** ```java 127.0.0.1:6379> watch balance OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> decrby balance 10 QUEUED 127.0.0.1:6379> incrby debt 10 QUEUED 127.0.0.1:6379> exec 1) (integer) 60 2) (integer) 40 ``` 有外部修改: 监控了Key,如果Key被修改了,后面一个事务的执行失效 ![Redis事务简介01.png][1] **unwatch** 当watch的对象有变更时,操作会失败,可以执行unwatch,取消之前的watch后的操作,再重新watch执行,直到成功 一旦执行了exec之前加的监控锁都会被取消掉 ### 总结 Watch指令,类似乐观锁,事务提交时,如果key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行 通过Watch命令在事务执行之前监控了多个Keys,倘若在Watch之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败 **阶段分析** 开启:以MULTI开始一个事务 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面 执行:由EXEC命令触发事务 **特性** 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到“这个让人万分头痛的问题 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚 [1]: https://lilinchao.com/usr/uploads/2020/03/289444940.png
标签:
Redis
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/761.html
上一篇
MySQL性能优化知识总结
下一篇
RabbitMQ知识总结
取消回复
评论啦~
提交评论
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
43
标签云
SpringBoot
正则表达式
nginx
Docker
Netty
Hbase
设计模式
MyBatisX
工具
数据结构
二叉树
前端
Spark RDD
并发编程
Http
Typora
容器深入研究
算法
Spark Streaming
Golang
Golang基础
Jenkins
Linux
Java工具类
序列化和反序列化
Nacos
高并发
稀疏数组
JavaScript
Thymeleaf
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞