Appearance
Redis 事务与Lua脚本
事务(Transaction)
基本命令
bash
# 开启事务
MULTI
# 命令入队
SET key1 value1
GET key1
INCR counter
# 执行事务
EXEC
# 取消事务
DISCARD事务特性
Redis事务保证:
- 原子性:事务中的命令要么全部执行,要么都不执行
- 顺序性:按FIFO顺序执行
- 隔离性:执行期间不会被其他客户端打断
注意:Redis事务不支持回滚!
WATCH命令
bash
WATCH mykey
GET mykey # 假设值为100
SET mykey 200
MULTI
SET mykey 300
EXEC # 如果mykey被其他客户端修改,返回nil原理:
- WATCH在事务开始前监控key
- EXEC时检查被监控的key是否被修改
- 如果修改,返回nil(事务不执行)
事务缺陷
- 不支持回滚
- 不支持原子性保证(某个命令失败后继续执行)
- 不支持隔离级别
Lua脚本
基本使用
bash
# 执行脚本
EVAL "return 'hello'" 0
EVAL "return redis.call('get', 'key')" 1 key
# 脚本缓存
SCRIPT LOAD "return ARGV[1]"
EVALSHA "c69d20ceca4713fe9a2bb93ce2cfdde38c2e2d2a" 0
# 脚本管理
SCRIPT FLUSH # 清空脚本缓存
SCRIPT EXISTS <sha1>Lua语法
lua
-- 变量
local name = "world"
-- 条件
if name == "world" then
return "hello " .. name
else
return "hi"
end
-- 循环
for i = 1, 3 do
print(i)
end
-- 函数
function getValue(key)
return redis.call('get', key)
end常用场景
lua
-- 原子计数器
local key = KEYS[1]
local current = redis.call('get', key)
if current then
return redis.call('incr', key)
else
redis.call('set', key, 1)
return 1
end面试考点
Q1: Redis事务与MySQL事务的区别?
答案:
| 特性 | Redis | MySQL |
|---|---|---|
| 回滚 | 不支持 | 支持 |
| 隔离级别 | 无 | ACID |
| 实现方式 | 乐观锁(WATCH) | MVCC + 锁 |
| 原子性 | 全执行/全不执行 | 可部分回滚 |
Q2: Lua脚本的优势?
答案:
- 原子性:脚本执行期间不会被其他命令打断
- 减少网络往返:多个命令打包执行
- 可自定义复杂逻辑
- 服务器端执行,减少延迟
Q3: 为什么Redis不支持事务回滚?
答案:
- Redis定位是简单KV存储,设计上追求高性能
- 命令失败通常是编程错误,应该早点发现
- 回滚会增加复杂度,影响性能
- 大多数分布式系统也不支持回滚(如Zookeeper)
Q4: WATCH的原理?
答案:
- WATCH记录监控的key
- 每次修改key时,Redis会记录version
- EXEC时检查version是否变化
- 变化则返回nil,否则执行事务
