不言不语

您现在的位置是: 首页 >  数据库  >  Redis

Redis

Redis 事务

2022-05-31Redis
Redis 中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,Redis 事务保证这些命令被执行时中间不会被任何其他操作打断。

一、什么是事务


Redis 中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,redis 事务保证这些命令被执行时中间不会被任何其他操作打断,也就是说,redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。


Redis事务的三个步骤:

1、开始事务

2、命令入队

3、执行事务


二、事务操作的命令


1、 multi 

语法: multi

作用:标记一个事务的开始。事务内的多条命令会按照先后顺序被放进一个队列当中。

返回值:总是返回 ok


2、exec

语法:exec

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

返回值:事务内的所有执行语句内容,事务被打断,返回 nil


3、discard

语法:discard

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

返回值:总是返回 ok


4、 watch

语法:watch key [key ...]

作用:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

返回值:总是返回 ok


5、 unwatch

语法:unwatch

作用:取消 watch 命令对所有 key 的监视。如果在执行 watch 命令之后, exec 命令 或 discard 命令先被执行了的话,那么就不需要再执行 unwatch了

返回值:总是返回 ok


三、事务的实现


1、正常执行事务


事务的执行步骤:首先开启事务,其次向事务队列中加入命令,最后执行事务提交

例 1:事务的执行: 

1)multi:用 multi 命令告诉 Redis,接下来要执行的命令你先不要执行,而是把它们暂时存起来(开启事务)

2)sadd works john 第一条命令进入等待队列(命令入队)

3)sadd works rose 第二条命令进入等待队列(命令入队)

4)exec 告知 redis 执行前面发送的两条命令(提交事务)


Redis事务.png


查看 works 集合


Redis事务.png


2、事务执行 exec 之前,入队命令错误(语法错误;严重错误导 致服务器不能正常工作(例如内存不足)),放弃事务。


执行事务步骤:

1)multi 正常命令

2)set key value 正常命令

3)incr 命令语法错误

4)exec 无法执行事务,那么第一条正确的命令也不会执行,所以 key 的值不会设置成功


Redis事务.png


结论:事务执行 exec 之前,入队命令错误,事务终止,取消,不执行。


3、事务执行 exec 命令后,命令执行错误,事务提交


执行步骤:

1)multi 正常命令

2)set username zhangsan 正常命令

3)lpop username 正常命令,语法没有错误,执行命令时才会有错误。

4)exec 正常执行,发现错误可以在事务提交前放弃事务,执行 discard.


Redis事务.png


结论:在 exec 执行后的所产生的错误,即使事务中有某个/某些命令在执行时产生了错误,事务中的其他命令仍然会继续执行。

Redis 在事务失败时不进行回滚,而是继续执行余下的命令。


Redis 这种设计原则是:Redis 命令只会因为错误的语法而失败(这些问题不能在入队时发现),或是命令用在了错误类型的键上面,失败的命令并不是 Redis 导致,而是由编程错误造成的,这样错误应该在开发的过程中被发现,生产环境中不应出现语法的错误。就是在程序的运行环境中不应该出现语法的错误。而 Redis 能够保证正确的命令一定会被执行。再者不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。


4、放弃事务


执行步骤:

1)  multi 开启事务

2)  set  age 25 命令入队

3)  set  age 30 命令入队

4)  discard 放弃事务,则命令队列不会被执行


Redis事务.png


五、Redis 的 watch 机制


1、 Redis 的 watch 机制


watch 机制原理:

watch 机制:使用 watch 监视一个或多个 key , 跟踪 key 的 value 修改情况,如果有 key 的 value 值在事务 EXEC 执行之前被修改了,整个事务被取消。EXEC 返回提示信息,表示事务已经失败。

watch 机制使的事务 EXEC 变的有条件,事务只有在被 watch 的 key 没有修改的前提下才能执行。不满足条件,事务被取消。使用 watch 监视了一个带过期时间的键,那么即使这个键过期了,事务仍然可以正常执行


2、何时取消 key 的监视(watch)? 


1)  watch 命令可以被调用多次。对键的监视从 watch 执行之后开始生效,直到调用 exec 为 止。不管事务是否成功执行,对所有键的监视都会被取消。

2)  当客户端断开连接时,该客户端对键的监视也会被取消。

3)  unwatch 命令可以手动取消对所有键的监视


watch指令类似于乐观锁,在事务提交时,如果watch监控的多个key中任何KEY的值已经被其他客户端更改,则使用exec执行事务时,事务队列将不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。


3、watch 的事例


A 客户端(红色):watch 某个 key,同时执行事务

B 客户端(黄色):对 A 客户端 watch 的 key 修改其 value 值。


1) 在 A 客户端设置 key : str.lp 登录人数为 10

2) 在 A 客户端监视 key : str.lp

3) 在 A 客户端开启事务 multi

4) 在 A 客户端修改 str.lp 的值为 11 

5) 在 B 客户端修改 str.lp 的值为 15  (重点看这里,str.lp已变化)

6) 在 A 客户端执行事务 exec

7) 在 A 客户端查看 str.lp 值,A 客户端执行的事务没有提交,因为 watch 的 str.lp 的值已经被修改了,所有放弃事务。


—— A客户端

Redis事务.png


—— B客户端

Redis事务.png


文章评论