Redis学习——Redis事务[通俗易懂]

Redis和传统的关系型数据库一样,因为具有持久化的功能,所以也有事务的功能! 面试官:请问Redis支持事务吗?如果支持和传统的关系型数据的事务有什么区别? 应试者:支持,但是是部分支持。

大家好,又见面了,我是全栈君。

Redis和传统的关系型数据库一样,因为具有持久化的功能,所以也有事务的功能!
有关事务相关的概念和介绍,这里就不做介绍。

学习Redis的事务之前,首先抛出一个面试的问题。

面试官:请问Redis支持事务吗?如果支持和传统的关系型数据的事务有什么区别?

应试者:支持,但是是部分支持。Redis的事务和传统的关系型数据库事务有点不一样,传统的数据库事务一组操作单元,要么全部成功,要么全都失败。而Redis在执行一个命令集合的时候,可能会出现集合的一些命令成功,一些命令失败。

Redis 事务-中文官网:Redis 事务管理

Redis 事务| 菜鸟教程 :Redis 事务

Redis事务的学习笔记总结:
1:是什么?

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

2:能做什么?

一个队列中,一次性、顺序性、排他性的执行一系列命令

3:常用命令
Redis 事务命令

1   DISCARD 
取消事务,放弃执行事务块内的所有命令。
2   EXEC 
执行所有事务块内的命令。
3   MULTI 
标记一个事务块的开始。
4   UNWATCH 
取消 WATCH 命令对所有 key 的监视。
5   WATCH key [key ...] 
监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

4:怎么玩?

  • 案例1:正常执行
127.0.0.1:6379> KEYS *
(empty list or set)
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> set k3 v3
QUEUED
127.0.0.1:6379> EXEC #执行,全部执行成功
1) OK
2) OK
3) OK
127.0.0.1:6379> MGET k1 k2 k3  #查看执行结果
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> 
  • 案例2:放弃事务
127.0.0.1:6379> MULTI #开始事务
OK
127.0.0.1:6379> set k4 v4 
QUEUED
127.0.0.1:6379> set k5 v5 
QUEUED
127.0.0.1:6379> set k1 v11  #这里发现出错了,第一次设置k1 了
QUEUED
127.0.0.1:6379> DISCARD #放弃事务
OK
127.0.0.1:6379> MGET k1 k2 k3 k4 k5      #k4 k5 的值没有设置成功
1) "v1"
2) "v2"
3) "v3"
4) (nil)
5) (nil)
127.0.0.1:6379> 
  • 案例3:全体连坐(一个出错,全部执行失败)
127.0.0.1:6379> KEYS *  #查看当前的keys
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> MULTI  #开始事务
OK
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> getandset k1  #这里有个操作出错 ,下面报错,
(error) ERR unknown command 'getandset'
127.0.0.1:6379> set k6 v6  # 这个命令依旧执行成功,放到Queued队列
QUEUED
127.0.0.1:6379> EXEC  #执行,出错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> MGET k1 k2 k3 k4 k5 k6    #k4 k5 k6 的值都没有设置成功,操作全部失败
1) "v1"
2) "v2"
3) "v3"
4) (nil)
5) (nil)
6) (nil)
127.0.0.1:6379> 
  • 案例4:冤头债主(一个出错,出错的不执行,其他的执行成功!)
127.0.0.1:6379> set k1 1  #将k1 修改为 1
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> MULTI  #开启事务
OK
127.0.0.1:6379> set k4 v4 
QUEUED
127.0.0.1:6379> set v5 v5
QUEUED
127.0.0.1:6379> INCR k1  #k1 加1 
QUEUED
127.0.0.1:6379> INCR k2 #k2 加1 ,因为k2的值为v2 ,这里最后执行会报错
QUEUED
127.0.0.1:6379> INCR k3 #k3 加1 
QUEUED
127.0.0.1:6379> set k6 v6
QUEUED
127.0.0.1:6379> EXEC   #执行,除了 k2 k3 执行失败,其他的都执行成功。
1) OK
2) OK
3) (integer) 2
4) (error) ERR value is not an integer or out of range    #INCR k2 执行出错
5) (error) ERR value is not an integer or out of range      #INCR k3 执行出错
6) OK
127.0.0.1:6379> MGET k1 k2 k3 k4 v5 k6  #看到k4 v5 k6 设置成功
1) "2"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
6) "v6"
127.0.0.1:6379> 
  • 案例5:watch监控(watch可以监控多个key,使用watch进行key的监控,相当于给key上锁,如果在事务中,监控的key的value发生变化,则整个事务的全部命令都执行失败)
127.0.0.1:6379> KEYS *
1) "k3"
2) "k4"
3) "k2"
4) "v5"
5) "k1"
6) "k6"
127.0.0.1:6379> MGET k1 k2 k3 k4 v5 k6
1) "2"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
6) "v6"
127.0.0.1:6379> WATCH k1  #监控k1 第一步
OK
127.0.0.1:6379> MULTI  #开始事务 第二步
OK
127.0.0.1:6379> set k7 v7    #第三步
QUEUED
127.0.0.1:6379> set k2 v2222  #第四步
QUEUED
127.0.0.1:6379> set k3 v3333  #第五步
QUEUED
127.0.0.1:6379> set k8 v8  #第六步
QUEUED
127.0.0.1:6379> EXEC  #第七步 #执行结果为nil ,说明执行失败
(nil)
127.0.0.1:6379> MGET k1 k2 k3 k4 v5 k6 k7 k8
1) "110"   #k1 的值被改了 ,其他的事务中的值都没有成功
2) "v2"
3) "v3"
4) "v4"
5) "v5"
6) "v6"
7) (nil)
8) (nil)
127.0.0.1:6379> 
--
在执行第三 —— 第六步之间,使用另一个客户端修改k1 的值为 成110 

另一个客服端执行:
127.0.0.1:6379> set k1 110
OK

案例5解释:因为另一个客服端修改 了k1的值,但是k1的值是被监控的,事务在执行的时候发现k1的值被修改了,则事务中的其他操作命令也不执行,即执行失败。

5:执行阶段

  1. 开启:以MULTI开始一个事务
  2. 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
  3. 执行/撤销:由EXEC/Discard 命令触发/撤销事务

6:总结

  • 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
  • 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

备注知识 :

悲观锁:

    悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block 直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁.

乐观锁:

    乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量, 乐观锁策略:提交版本必须大于记录当前版本才能执行更新

CAS(check and set)

悲观锁和乐观锁相关的参考博文:
Java 中的悲观锁和乐观锁的实现:https://toutiao.io/posts/400085/app_preview
乐观锁的一种实现方式:CAS:http://blog.csdn.net/qq32933432/article/details/51036361


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页:http://blog.csdn.net/u010648555

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/121160.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 静态代码检查报告

    静态代码检查报告今天在下面刊载一篇小王同学写的静态代码检查报告 图文并茂 条理清晰 1 工具说明 FindBugs 是一个静态分析工具 它检查类或者 JAR 文件 将字节码与一组缺陷模式进行对比以发现可能的问题 有了静态分析工具 就可以在不实际运行程序的情况对软件进行分析 不是通过分析类文件的形式或结构来确定程序的意图 而是通常使用 Visitor 模式 Findbugs 可以

    2025年11月16日
    4
  • 虚拟存储

    虚拟存储为解决日益增长的内存需要,有以下几种解决办法:1.覆盖:将程序划分成几个模块,将没有调用关系的模块(即不会同时运行的模块)分成一组,其中每组所占的内存大小为组内所需内存最大的模块的内存,然后一组内

    2022年7月2日
    26
  • java 输出_java怎么输出

    java 输出_java怎么输出展开全部java控制台输出由print()和println()来完成最为简单。这两种方法由rintStream(System.out引用32313133353236313431303231363533e78988e69d8331333365643661的对象类型)定义。尽管System.out是一个字节流,用它作为简单程序的输出是可行的。因为PrintStream是从OutputStrea…

    2022年7月7日
    36
  • 如何使用fdisk

    如何使用fdisk

    2021年7月27日
    60
  • linux解压zip多种命令,Linux常用几种打包、压缩、解压命令,(备用)

    linux解压zip多种命令,Linux常用几种打包、压缩、解压命令,(备用)01-.tar格式解包:[*******]$tarxvfFileName.tar打包:[*******]$tarcvfFileName.tarDirName(注:tar是打包,不是压缩!)02-.gz格式解压1:[*******]$gunzipFileName.gz解压2:[*******]$gzip-dFileName.gz压缩:[*******]$gzipFile…

    2022年6月1日
    42
  • 智能营销增益模型(Uplift Modeling)的原理与实践

    智能营销增益模型(Uplift Modeling)的原理与实践文章目录增益模型因果与推论(CausalInference)增益模型的表示差分响应模型(Two-ModelApproach)模型优缺点差分响应模型升级版(One-ModelApproach)ClassTransformationMethodClassTransformation的两个假设ModelingUpliftDirectly增益模型的评估uplift柱状图Qini曲线(Qi…

    2025年8月22日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号