一个Redis事务,可以让你征服面试官半小时。

理解原子性

我们知道,java中的 i++ 或者 ++i 这些自增操作不具备原子性,因为自增操作在我们代码层面是一个指令,但是在 jvm 底层,它分为这两个步骤:

  1. 从局部变量表中读取 i 的值压入操作数栈
  2. 将局部变量表中 i 的值加1

若 jvm 在执行第 1 步的时候,其他线程先于这个线程改变了 i 的值,然后执行第二步后得出的值就不是我们希望的。

在 redis 中也有类似的自增操作,如我们之前学的 string 数据类型中的 incr 指令,它可以对一个 integer 类型的值加1。但是 incr 指令与 java 自增不一样的是,它是一个原子操作,因为 incr 是调用操作系统底层的指令,它不会被其他线程打断。所以 incr 指令具有原子性。

为什么叫原子性?

原子性其实就是有类似原子的性质,我们知道原子中有质子和中子,他们构成了原子,不可分割,如果分割了,就不是一个原子了,是不是很好理解。整理redis的同时也整理了最近两个月最新的面试题。需要的朋友可以点击:这个,点这个!!,备注:csdn。
在这里插入图片描述

什么是事务

事务就是指一系列操作,这些操作要么同时成功,要么同时失败,它是一种原子操作。原子就是一个整体,不可分割,事务中的这些操作也是一样。
假设有这样一个场景:张三向李四转账 100 块钱,最少需要经历两个步骤

  1. 张三的银行卡中钱减100块
  2. 李四的银行卡中钱加100块

在没有事务的情况下,可能会导致 1 号操作执行成功,2 号操作执行失败,那结果是张三的钱少了 100 块,李四的钱却没增加,张三的 100 块凭空消失了,这肯定会出问题,所以这两部操作必须要放在事务中执行,要么转账成功,要么转账失败,这就是事务的作用。

redis事务

redis 是单线程的程序,每个指令都保证原子性,但是不保证多个指令的原子性。
当有多个客户端连接同一个 redis 时,客户端之间会竞争cpu资源,来争夺 rdis 指令的执行权,所以如果一个 client 要执行一系列指令时,可能会被其他客户端打断。

要使多个指令也具有原子性,可以使用 redis 事务
redis 事务保证两点:

  1. 执行一个事务时,所有的命令都会被顺序执行,且不会被其他客户端打断
  2. 执行一个事务时,所有命令要么同时成功,要么同时失败

如果 redis 开启 AOF 模式,在执行 redis 事务之前,redis 会先把事务写在磁盘中再执行命令。如果事务执行到一半,redis 进程突然就挂了,那么就会导致事务中只有一部分指令执行成功,还有一部分指令还未执行。这种情况下,在 redis 下一次启动时会检测到错误,并退出 redis。使用 redis-check-aof 工具可以对 AOF 文件进行修复,删除掉磁盘中的未执行成功的事务,然后重新启动加载 AOF 文件,redis 就恢复到事务没有执行创建的状态,就可以正常启动了

事务相关的命令

和 redis 事务有关的指令有:

扫描二维码关注公众号,回复: 11902286 查看本文章
  • multi
  • exec
  • discard

下面开始介绍每个命令

multi

使用 multi 指令来开启事务

127.0.0.1:6379> set zhangsan 1000
OK

127.0.0.1:6379> set lisi 1000
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> incrby zhangsan -100
QUEUED

127.0.0.1:6379> incrby lisi 100
QUEUED

multi 指令返回 ok,证明事务开启成功。
开启事务后,接下来执行每条正确的指令都返回 QUEUE,代表命令被放入等待队列,但并没有执行。

exec

使用 exec 命令来执行事务

127.0.0.1:6379> set zhangsan 1000
OK

127.0.0.1:6379> set lisi 1000
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> incrby zhangsan -100
QUEUED

127.0.0.1:6379> incrby lisi 100
QUEUED

127.0.0.1:6379> exec   # 执行事务
1) (integer) 900
2) (integer) 1100

使用 exec 执行事务后,会按顺序返回事务中每天指令的返回结果。
还整理了Java核心的知识点,大家也可以看看。需要的朋友可以点击:这个,点这个!!,备注:csdn。
在这里插入图片描述

discard

如果事务创建成功,但你又不想执行了,使用 discard 命令来取消

127.0.0.1:6379> multi                  # 开启事务
OK

127.0.0.1:6379> incrby zhangsan -100
QUEUED

127.0.0.1:6379> incrby lisi 100
QUEUED

127.0.0.1:6379> discard                 # 取消事务
OK

redis 事务乐观锁

乐观锁,即认为所有时候都不会出现问题,它不会去加锁,他会在修改数据的时候判断这个数据是否被改动过,如果没有被其他人改动过,就更新数据。

在 redis 中也有乐观锁的操作,来防止数据出现问题,现在有如下一个场景:

你想通过事务对 redis 中的 key/value 进行修改,在没有执行 exec 命令之前,这时候另一个 client 修改了这个 key/value,这样再执行 exec 后可能会出现问题。这种情况下用 redis 的乐观锁操作就可以很轻松解决
在 redis 中有一种 check and set(CAS)的乐观锁操作,相关命令如下

  • watch
  • unwatch

watch

通过 watch 命令来监视这个 key/value,如果发现该 key/value 被修改,则调用 exec 时事务不会被执行

127.0.0.1:6379> watch zhangsan lisi   # 监视 zhangsan 和 lisi
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> incrby zhangsan -100
QUEUED

127.0.0.1:6379> incrby lisi 100
QUEUED

================ 这时候zhangsan的值被其他客户端修改=======================

127.0.0.1:6379> exec   # 事务执行失败
(nil)

unwatch

取消监视,与 watch 命令相对
在执行 exec 后,不管是否执行成功,watch 命令都会 unwatched
客户端退出后,watch 命令也会 unwatched

127.0.0.1:6379> watch zhangsan lisi   # 监视 zhangsan 和 lisi
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> incrby zhangsan -100
QUEUED

127.0.0.1:6379> incrby lisi 100
QUEUED

127.0.0.1:6379> unwatch  # 取消监视
OK

和事务相关的错误

在 redis 事务中,可能会发生两种错误

1、编译型错误

在 multi 后,exec 调用之前,由于输入不正确的 redis 命令导致的错误

127.0.0.1:6379> multi
OK

127.0.0.1:6379> sets zhangsan 22   # 事务中命令输错
(error) ERR unknown command `sets`, with args beginning with: `zhangsan`, `22`, 

127.0.0.1:6379> set zhangsan 22
QUEUED

127.0.0.1:6379> exec   # 事务执行不成功
(error) EXECABORT Transaction discarded because of previous errors.

在这种情况下事务不会执行成功

2、运行时错误

在 exec 调用之后,由于 redis 命令执行不成功导致的错误

127.0.0.1:6379> set test abc
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> incr test   # 由于test中存的不是 integer,在exec时会出错
QUEUED

127.0.0.1:6379> set info aaa
QUEUED

127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK

从执行结果看出,在 exec 时,即使其中有命令出错,后面的命令不会被影响,依旧会被执行从这里也可以看出,redis 不支持回滚

最后提供免费的Java架构学习资料,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

点击:点这个!点这个!暗号:csdn。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/HarderXin/article/details/109084021