Skip to content

面试速答(先看这里)

**一句话结论:**Redis中是支持事务的,他的事务主要目的是保证多个命令执行的原子性,即要在一个原子操作中执行,不会被打断。

60秒标准回答:

Redis中是支持事务的,他的事务主要目的是保证多个命令执行的原子性,即要在一个原子操作中执行,不会被打断

需要注意的是, Redis的事务是不支持回滚的 。从 Redis 2.6.5 开始,服务器将会在累积命令的过程中检测到错误。然后,在执行 EXEC 期间会拒绝执行事务,并返回一个错误,同时丢弃该事务。如果事务执行过程中发生错误,Redis会继续执行剩余的命令而不是回滚整个事务

Errors happening after EXEC instead are not handled in a special way: all the other commands will be executed even if some command fails during the transaction.

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**需要注意的是, Redis的事务是不支持回滚的 。
  • **要点2:**前面我们提到过,从 Redis 2.6.5 开始,服务器将会在累积命令的过程中检测到错误。
  • **要点3:**Redis错误有两种情况,一种是在命令排队的过程就就检测到的错误,比如语法错误,比如内存不够了,等等。
  • **要点4:**而后面这种错误,Redis认为是不应该出现的。
  • **要点5:**下面是一个使用Jedis客户端,借助事务实现电商下单的例子:

**记忆锚点:**Redis → EXEC → key → WATCH → the → transaction

易错提醒:

  • 需要注意的是, Redis的事务是不支持回滚的 。
  • 在这种错误,会在调用 EXEC 后,命令可能会直接失败。

加分表达:

  • 如果事务执行过程中发生错误,Redis会继续执行剩余的命令而不是回滚整个事务。
  • WATCH key [key ...]: 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

追问准备:

  • 事务执行时会有什么错误?
  • 这里是不是矛盾了?

典型回答 ​

Redis中是支持事务的,他的事务主要目的是保证多个命令执行的原子性,即要在一个原子操作中执行,不会被打断。

需要注意的是,Redis的事务是不支持回滚的。从 Redis 2.6.5 开始,服务器将会在累积命令的过程中检测到错误。然后,在执行 EXEC 期间会拒绝执行事务,并返回一个错误,同时丢弃该事务。如果事务执行过程中发生错误,Redis会继续执行剩余的命令而不是回滚整个事务。

> Errors happening after EXEC instead are not handled in a special way: all the other commands will be executed even if some command fails during the transaction. > > https://redis.io/docs/interact/transactions/#errors-inside-a-transaction

更多原子性的解释参考:

📄 ✅为什么Lua脚本可以保证原子性?

打开文档:✅为什么Lua脚本可以保证原子性?

Redis事务相关的命令主要有以下几个:

  • MULTI:标记一个事务块的开始。

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

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

  • UNWATCH:取消 WATCH 命令对所有 key 的监视。

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

​

事务执行时会有什么错误? ​

前面我们提到过,从 Redis 2.6.5 开始,服务器将会在累积命令的过程中检测到错误。但是后面又说事务执行时也会有错误。这里是不是矛盾了?

其实并不矛盾。

Redis错误有两种情况,一种是在命令排队的过程就就检测到的错误,比如语法错误,比如内存不够了,等等。在这种错误,会在调用 EXEC 后,命令可能会直接失败。

还有一种错误,是在调用 EXEC 后,命令执行过程中出现的错误,最常见的就是操作类型不一致,比如对字符串进行列表相关的操作。这种就是在执行过程中才会出现的。

而后面这种错误,Redis认为是不应该出现的。所以需要在开发阶段就避免,这也是他没有提供回滚的一个重要原因。

扩展知识 ​

例子 ​

下面是一个使用Jedis客户端,借助事务实现电商下单的例子:

plain
Jedis jedis = new Jedis("localhost", 6379);

// 开启事务 : MULTI
Transaction tx = jedis.multi();

// 扣减库存
tx.decrBy("item:10001:stock", 1);

// 计算商品总价
tx.mul(100, 2);

// 下单记录
tx.rpush("orders", "user:10001,item:10001,amount:2,total:200");

// 执行事务 : EXEC
List<Object> result = tx.exec();

// 检查事务执行结果
if (result == null) {
    System.out.println("事务执行失败!");
} else {
    System.out.println("事务执行成功,订单已提交!");
}

事务和pipeline的区别 ​

📄 ✅什么是Redis的Pipeline,和事务有什么区别?

打开文档:✅什么是Redis的Pipeline,和事务有什么区别?

事务和Lua的区别 ​

📄 ✅Redis的事务和Lua之间有哪些区别?

打开文档:✅Redis的事务和Lua之间有哪些区别?