Redis —— 事务

lalala / 2023-07-28 / 原文

参考:

小林:https://xiaolincoding.com/redis/base/redis_interview.html

shuxiaohua(集群):https://huaweicloud.csdn.net/637f776ddacf622b8df84ee9.html

java guide: https://javaguide.cn/database/redis/redis-questions-02.html

 

一 Pipeline

管道技术(Pipeline)是客户端提供的一种批处理技术,用于一次处理多个 Redis 命令,使用管道技术可以解决多个命令执行时的网络等待,它是把多个命令整合到一起发送给服务器端处理之后统一返回给客户端(服务端是多次响应),这样就免去了每条命令执行后都要等待的情况,从而有效地提高了程序的执行效率。

但使用管道技术也要注意避免发送的命令过大,或管道内的数据太多而导致的网络阻塞。

要注意的是,管道技术本质上是客户端提供的功能,而非 Redis 服务器端的功能。

pipeline并不是redis的设计,只要是基于TCP的长连接,而且访问协议为简单请求/应答,都能去实现pipeline。

如上图所示,客户端一次发送一批命令给服务端,客户端一次解析多个响应结果。

Pipline 是原子的吗?

管道不是原子的。想象一下,有 2 个客户端连接与同一个 Redis 服务器通信,并且两者同时发送一个由 5 个命令组成的管道。虽然可以保证来自客户端 1 管道的所有命令都将按顺序执行,但不能保证它们不会与来自客户端 2 管道的命令交错。

 

 

 二 Redis 事务

Redis 可以通过 MULTIEXECDISCARD 和 WATCH 等命令,以及客户端 pipeline 来实现事务(Transaction)功能。

  • multi:用于标记事务块的开始,Redis会将同一个客户端连接后续的命令逐个放入队列中,然后使用exec原子化地执行这个命令队列
  • exec:执行命令队列
  • discard:清除命令队列
  • watch:监视key。开启MULTI事务之前输入wacth命令,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的 Key 被 其他客户端/Session 修改的话,整个事务都不会被执行。
  • unwatch:清除监视key

multi 用法

> MULTI
OK
> SET PROJECT "JavaGuide"
QUEUED
> GET PROJECT
QUEUED
> EXEC
1) OK
2) "JavaGuide"

discard 用法

#读取 count 的值4
127.0.0.1:6379> GET count
"1"
#开启事务
127.0.0.1:6379> MULTI 
OK
#发送事务的第一个操作,对count减1
127.0.0.1:6379> DECR count
QUEUED
#执行DISCARD命令,主动放弃事务
127.0.0.1:6379> DISCARD
OK
#再次读取a:stock的值,值没有被修改
127.0.0.1:6379> GET count
"1"

watch 用法

# 客户端 1
> SET PROJECT "RustGuide"
OK
# 在 MULTI 前 WATCH
> WATCH PROJECT
OK
> MULTI
OK
> SET PROJECT "JavaGuide"
QUEUED

# 客户端 2
# 在客户端 1 WATCH 后,执行 EXEC 命令提交事务之前,修改 PROJECT 的值
> SET PROJECT "GoGuide"

# 客户端 1
# 修改失败,因为 PROJECT 的值被客户端2修改了
> EXEC
(nil)
> GET PROJECT
"GoGuide"

Multi 是原子的吗?

muti 中的命令是一个个发给服务端的

刚开始我想到的一个问题是,如果

注意这里的 “同一个客户端” 是指同一个 tcp 连接,而不是同一个进程,一个比如 java 应用进程,一般会使用连接池与 redis 建立多个连接,

Multi 可以实现事务的原子性吗?

原子性(Atomicity):一个事务中的所有操作,不可分割,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。

redis 事务可以保证一个事务中的所有操作不可分割,不被别的命令打断。那么 redis 可以保证事务在执行过程中发生错误而回滚吗?