李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
Redis事务简介
Leefs
2020-03-20 PM
1791℃
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
47
NLP
4
标签云
Thymeleaf
JavaSE
DataX
Livy
Quartz
算法
SpringCloudAlibaba
HDFS
微服务
Http
Golang
Kibana
Spark SQL
GET和POST
哈希表
JavaWEB项目搭建
正则表达式
线程池
查找
递归
Scala
FileBeat
MyBatis-Plus
Yarn
SpringCloud
pytorch
Spark Streaming
Filter
排序
RSA加解密
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭