redis的事务相关概述

1、是什么?

我们学过sql一定就知道事务,那么redis作为一个nosql(not only sql)也一定有自己的事务
redis的事务:可以一次性执行多条命令,本质是一组命令的集合,一个事务中的所有命令都会被序列化,按顺序的串行化执行,而不会被其他命令插入,不允许加塞。

简单说就是:一个队列中,一次性、顺序性、排他性的执行一系列命令

2、 怎么用?

2、1 几个基本命令

  • multi 用于标记一个事务块的开始,之后所有的命令都放在队列,等遇到exec命令的时候再执行
  • exec 用于事务块内所有命令的执行,如果命令被中断,放回false
  • watch 用于监视一个或多个key,如果在事务执行之前这个或(这些)key 被其他命令所改动,事务将被中断
  • unwatch 用于取消watch命令对所有key的监视

2、2 事务的正常执行

我们先使用multi命令开启事务,然后每一次操作都会放入队列queued中,知道执行exec,所有的命令都会按顺序执行。
在这里插入图片描述

2、3 放弃事务

我们可以使用discard命令终止当前事务,所有的命令都不会被执行
在这里插入图片描述

2、4 全体连坐

当我们在事务中使用了一条不合规矩的命令,就会出现异常,本次事务的所有指令都不会被执行
在这里插入图片描述

2、5 冤有头债有主

我们使用的一条语句,但是并不是编译出错,而是数据本身出问题,那么当前指令不会被执行,而事务中的其他正常指令仍然可以执行。
在这里插入图片描述
在这个例子中,我们可以看到,name的类型是一个string,incr之后会出现not an integer的异常,但是age是一个integer,可以执行incr,再事务结束以后,对name进行的incr操作出现了异常,但是没有影响到其他的操作。

2、6 watch监控

在这里我们要提一下乐观锁和悲观锁以及CAS

  • 乐观锁:顾名思义,这个锁它认为我的数据很安全,每次去拿数据的时候,我们认为别人都不会进行修改,所以不上锁,但是在更新的时候会判断一下,在此期间,别人有没有对我这个数据进行了修改,可以使用一个版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
    乐观锁的策略:提交的时候的版本号必须大于记录的版本号才能执行更新。
  • 悲观锁:顾名思义,就是很悲观,它认为每次去拿数据都会被别人修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里面很多就用到了这种锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前先上了锁。
  • CAS(check and set)

watch的理解
在redis中使用watch可以解决事务是执行还是会滚,一般而言,我们在multi命令之前,使用watch明亮监控某些键值对,然后使用multi命令来进行事务操作。当使用exec命令的时候,我们会先去对比watch命令监控的键值对的版本,看它是否是同一个版本,如果没有发生变换,就执行事务中的操作,如果发生了改变,就会回滚,所有命令都不执行。这里可以对比乐观锁这个概念。
在这里插入图片描述

这里我们简单通过一个例子来说明
下面是一个正常的事务,balance代表信用卡额度,debt代表我们与银行的债务,当我们用信用卡消费30元的时候,balance-30 debt+30
在这里插入图片描述
无加塞,监听余额后开启事务、
在这里插入图片描述
有加塞,监听后在事务之前修改了余额
在这里插入图片描述
一旦监听了key,如果key被修改了,后面的一个事务都会执行失败。

unwatch
在这里插入图片描述
我们可以通过unwatch取消对所有key的监控。
注意:我们一旦执行了exec,之前加的监控锁都会被取消掉了。
总结
watch指令,类似于乐观锁,事务提交时,如果key的值已经被别的客户端改变,比如list已经被别的客户端push/pop过了,整个事务队列都不会被执行。
通过watch命令在事务执行之前已经监控了多个keys,倘若在watch之后,有任何key的值发生了变化,exec命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者执行失败。

3、事务的三个阶段和三个特性

三阶段:

  • 开启:以multi开始就一个事务
  • 入队:将多个命令入队列到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列中
  • 执行:由exec命令触发事务

三特性

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

猜你喜欢

转载自blog.csdn.net/l2470334493/article/details/108936824