• Redis事务操作


    Redis事务操作

    每个公司每个项目可能有不同的引入方式,但是最基本的都大差不差,所以这里只展示最基本的。

    redis事务定义

    redis事务是一个单独的隔离操作,事务中的所有命令都会序列化、按顺序地执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

    redis事务的主要作用就是串联多个命令防止别的命令插队。

    Multi、Exec、discard

    从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,redis会将之前的命令依次执行。

    组队的过程中可以通过discard来放弃组队。

    redis事务分2个阶段:组队阶段、执行阶段

    • 组队阶段:只是将所有命令加入命令队列
    • 执行阶段:依次执行队列中的命令,在执行这些命令的过程中,不会被其他客户端发送的请求命令插队或者打断。
    相关的几个命令

    multi:标记一个事务块的开始

    标记一个事务块的开始。

    事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由exec命令原子性(atomic)地执行。

    示例:

    127.0.0.1:6379> multi		#开启事务
    OK
    127.0.0.1:6379> incr id		#incr将id的值+1,id不存在会被初始化为0
    QUEUED						#表示这个命令加入队列了,还没有被执行
    127.0.0.1:6379> incr id
    QUEUED
    127.0.0.1:6379> incr id
    QUEUED
    127.0.0.1:6379> ping		#ping用来判断服务器运作正常的话,返回PONG
    QUEUED
    127.0.0.1:6379> exec		#以上几个命令依次执行
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    exec:执行所有事务块内的命令

    执行所有事务块内的命令。

    假如某个(或某些)key正处于watch命令的监视之下,且事务块中有和这个(或这些)key相关的命令,那么exec命令只在这个(或这些)key没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。

    如果exec执行成功,会返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值nil。

    示例1:

    #客户端1
    127.0.0.1:6379> watch userid username	#监听userid和username
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set userid 1001			#设置userid为1001
    QUEUED
    127.0.0.1:6379> incr userid				#userid自加1
    QUEUED
    127.0.0.1:6379> exec					#单客户端下执行成功
    1) OK
    2) (integer) 1002
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    示例2:

    #客户端1
    127.0.0.1:6379> flushdb #方便测试
    127.0.0.1:6379> watch userid username
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set userid 1001
    QUEUED
    #此时开启客户端2
    #等待客户端2设置username之后,再执行exec
    127.0.0.1:6379> exec
    (nil)					#返回nil,是因为其他客户端操作了username,事务执行失败
    
    #客户端2
    127.0.0.1:6379> set username "张三" #将username设置为“张三”
    OK
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    discard:取消事务

    取消事务,放弃执行事务块内的所有命令。

    示例:

    redis> multi
    OK
    redis> ping
    QUEUED
    redis> SET hi "hello"
    QUEUED
    redis> discard
    OK
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    事务的错误处理

    情况1:组队中命令有误,导致所有命令取消执行

    组队中某个命令出现了错误报告,执行时整个队列中所有的命令都会被取消。

    示例代码:

    #事务中执行了3个set命令,而第3个命令“set address”命令本身有问题,加入队列失败
    #最后执行exec的时候,所有的命令都被取消执行。
    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> multi #开启一个事务块
    OK
    127.0.0.1:6379(TX)> set name ready
    QUEUED
    127.0.0.1:6379(TX)> set age 30
    QUEUED
    127.0.0.1:6379(TX)> set address #命令有问题,导致加入队列失败
    (error) ERR wrong number of arguments for 'set' command
    127.0.0.1:6379(TX)> exec #执行exec的时候,事务中所有命令都被取消
    (error) EXECABORT Transaction discarded because of previous errors.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    情况2:组队中没有问题,执行中部分成功部分失败

    命令组队的过程中没有问题,执行中出现了错误会导致部分成功部分失败。

    示例代码:

    #事务中有3个命令,3个命令都入队列成功了
    #执行exec命令的时候,1和3命令成功了,第2个失败了
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> set k1 v1 #命令1:设置k1的值为v1
    QUEUED
    127.0.0.1:6379(TX)> incr k1 #命令2:k1的值递增1,由于k1的值不是数字,执行的时候会失败的
    QUEUED
    127.0.0.1:6379(TX)> set k2 v2 #命令3:设置k2的值为v2
    QUEUED
    127.0.0.1:6379(TX)> exec #执行命令,1和3命令成功,第2个失败了
    1) OK
    2) (error) ERR value is not an integer or out of range
    3) OK
    127.0.0.1:6379> mget k1 k2 #查看k1和k2的值
    1) "v1"
    2) "v2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    事务冲突的问题

    我们学习的时候经常会碰到这样的假设:账户中只有10000,有多个人使用你的账户,同时去参加双十一抢购

    一个请求想给金额减8000

    一个请求想给金额减5000

    一个请求想给金额减1000

    在这里插入图片描述

    3个请求同时看到的余额都是10000,大于操作金额,都去执行修改余额的操作,最后导致金额变成了-4000,这显然是有问题的。

    悲观锁

    在这里插入图片描述

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

    乐观锁

    在这里插入图片描述

    乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去那数据的时候都认为别人不会修改,所以不会上锁,但是在修改的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。redis就是使用这种check-and-set机制实现事务的。

    watch key [key …]

    在执行multi之前,先执行watch key1 [key2 …],可以监视一个或者多个key,若在事务的exec命令之前这些key对应的值被其他命令所改动了,那么事务中所有命令都将被打断,即事务所有操作将被取消执行。

    上面章节以给出相关示例:

    #客户端1
    #客户端1用watch监控userid和username
    127.0.0.1:6379> watch userid username
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set userid 1001
    QUEUED
    #此时开启客户端2
    #等待客户端2设置username之后,再执行exec
    127.0.0.1:6379> exec
    (nil)					#返回nil,是因为其他客户端操作了username,事务执行失败
    
    
    
    #客户端2执行操作
    127.0.0.1:6379> set username "张三" #将username设置为“张三”
    OK
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    unwatch:取消监视

    取消watch命令对所有key的监视。

    如果在执行watch命令之后,exec命令或discard命令先被执行了的话,那么就不需要再执行unwatch了。

    因为exec命令会执行事务,因此watch命令的效果已经产生了;而discard命令在取消事务的同时也会取消所有对key的监视,因此这两个命令执行之后,就没有必要执行unwatch了。

    示例:

    127.0.0.1:6379> watch userid username
    OK
    127.0.0.1:6379> unwatch
    OK
    
    • 1
    • 2
    • 3
    • 4

    redis事务三特性

    (1)单独的隔离操作

    事务中的所有命令都会序列化、按顺序地执行,事务在执行过程中,不会被其他客户端发送来的命令请求所打断。

    (2)没有隔离级别的概念

    队列中的命令没有提交(exec)之前,都不会实际被执行,因为事务提交前任何指令都不会被实际执行。

    (3)不能保证原子性

    事务中如果有一条命令执行失败,后续的命令仍然会被执行,没有回滚。

    如果在组队阶段,有1个失败了,后面都不会成功;如果在组队阶段成功了,在执行阶段有那个命令失败就这条失败,其他的命令则正常执行,不保证都成功或都失败。

  • 相关阅读:
    为什么电力公司很少用轨道式的电表?
    怎么把amr格式转换成mp3?
    uniapp学习笔记 真机运行遇到的问题
    Mac配置iTerm样式终端
    Go语言学习笔记——日期时间处理库Carbon
    “鲜切花+”模式开启,昆明首个鲜切花行业集合体空间开业
    【unity3D插件】Embedded Browser(ZFBrowser) — 快速实现PC端内嵌网页(有详细图解)
    【线程】多线程安全
    TensorFlow学习(3)初始化&非饱和激活函数&批量归一化&梯度剪裁&迁移学习&优化器
    NLP模型笔记2022-33:Sentence-BERT STS模型列表与预训练方法
  • 原文地址:https://blog.csdn.net/lili40342/article/details/127915924