Redis 事务
2022年10月13日大约 3 分钟约 1021 字
1. Redis 事务特性
Redis 事务具有两个重要特性:
- 单独的隔离操作:事务中的所有命令都会被序列化,它们将按照顺序执行,并且在执行的过程中,不会被其他客户端发送来的命令打断。
- 不保证原子性:在 Redis 的事务中,如果存在命令执行失败的情况,那么其他命令依然会被执行,不支持事务回滚机制。
注意,Redis 不支持事务回滚,原因在于 Redis 是一款基于内存的存储系统,其内部结构比较简单,若支持回滚机制,则让其变得冗余,并且损耗性能,这与 Redis 简单、快速的理念不相符合。
Redis 事务的目的是方便用户一次执行多个命令。执行 Redis 事务可分为三个阶段:
- 开始事务:标志开启一个事务。
- 命令入队:命令进入队列,但不会执行。此阶段如果发生错误,则整个队列的命令失效,意味着这个事务完全失败了。
- 执行事务:事务中各命令的真正执行。此阶段如果发生错误,事务中的命令依旧会顺序执行,命令之间互不影响。
Redis 的解决事务冲突的锁机制是乐观锁。
2. Redis 事务命令
命令 | 说明 |
---|---|
MULTI | 开启一个事务 |
EXEC | 执行事务中的所有命令 |
DISCARD | 放弃组队,取消事务 |
WATCH key [key ...] | 在开启事务之前用来监视一个或多个 key ,如果事务执行前这些 key 被改动过,那么事务将被打断 |
UNWATCH | 取消 WATCH 命令对 key 的监控 |
3. Lua 脚本
Lua 是一种轻量小巧、开源的脚本语言,用标准 C 语言编写。其设计目的就是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。它被广泛的应用于:游戏开发、独立应用脚本、Web 应用脚本、扩展和数据库插件等。
虽然 Redis 官网提供了丰富指令集(200 多个),但是在某些特定的领域需要对指令进行扩充,因此 Redis 允许我们使用 Lua 语言以自定义的方式编写脚本命令,这满足了一部分用户的需求。Redis 服务器会以单线程、原子性的方式执行 Lua 脚本,保证 Lua 脚本在处理过程中不会被其他请求中断。
使用 Lua 脚本有如下好处:
- 减少网络开销:可以将多个请求通过脚本的形式一次发送,从而减少网络时延,比如本来 10 次网络请求,我们就可以通过 Lua 脚本一次性完成。
- 原子操作:Redis 会将整个脚本作为一个整体执行,中间不会被其他请求干扰。因此在脚本运行过程中无需使用事务。
- 脚本复用:客户端发送的脚本会一直存储在 Redis 中,这样其他客户端只需对这个脚本稍作修改就可以达到复用的目的,极大地提升了编写脚本的效率。
由于乐观锁导致的一些问题,如秒杀业务中的库存遗留问题,可考虑用 Lua 脚本来解决。通过 lua 脚本解决争抢问题,实际上是 redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题。
Redis 中关于 Lua 脚本的命令:
命令 | 说明 |
---|---|
EVAL script numkeys key [key ...] arg [arg ...] | 使用 Lua 解释器执行脚本 |
EVALSHA sha1 numkeys key [key ...] arg [arg ...] | Lua 解释器根据 sha1 校验码执行脚本 |
SCRIPT EXISTS script [script ...] | 查看指定的脚本是否保存在于缓存当中 |
SCRIPT FLUSH | 从脚本缓存中移除所有脚本 |
SCRIPT KILL | 杀死当前正在运行的 Lua 脚本 |
SCRIPT LOAD script | 将脚本 script 添加到脚本缓存中,但不马上执行这个脚本 |