首页 > lua脚本是什么,有什么用,以及怎么用?

lua脚本是什么,有什么用,以及怎么用?

一、我们之前遇到了什么问题?(必须先懂)

我们之前写释放锁的代码是这样的:

java

运行

// 1. 判断锁是不是自己的
String id = stringRedisTemplate.opsForValue().get(key);
if(threadId.equals(id)){
    // 2. 是自己的,才删除
    stringRedisTemplate.delete(key);
}

这段代码不是原子的!

它分成 2 步

  1. (判断是不是我的锁)
  2. (释放锁)

高并发下会发生恐怖的事情:

  1. 线程 A 查询 → 是我的锁
  2. 刚查完,突然卡住了!
  3. 锁超时过期 → Redis 自动删了
  4. 线程 B 抢到锁
  5. 线程 A 恢复 → 直接删锁!
  6. 线程 A 把线程 B 的锁删了!

二、为什么会发生?

因为 查询 和 删除 是两步!中间可以被打断!

plaintext

查询 → 卡住 → 锁超时 → 别人上锁 → 你删除 → 删错锁!

三、怎么解决?

必须让 查询 + 删除 变成一步执行,不能被打断!

谁能做到?

Lua 脚本!

四、Lua 脚本怎么实现原子性?

原理超级简单:

Redis 执行 Lua 脚本时,会把整个脚本当成一条命令!

中间不允许任何其他命令插入!

绝对不被打断!

五、黑马点评里的 Lua 脚本(释放锁)

lua

-- 1. 获取锁中的线程标识
local id = redis.call('get', KEYS[1])

-- 2. 比较是否是自己的线程
if id == ARGV[1] then
    -- 3. 是自己的,删除锁
    return redis.call('del', KEYS[1])
end

-- 4. 不是自己的,直接返回 0
return 0

这一段代码在 Redis 中是 一步执行

六、Lua 脚本如何保证原子性?(最核心)

在 Redis 中,Lua 脚本是独占执行的!

意思:

  • Redis 单线程执行 Lua
  • 执行期间,其他命令必须排队!
  • 查询 和 删除 绝对连在一起,不可能被打断!

七、用了 Lua 之后,恐怖场景彻底消失!

流程变成:

  1. 线程 A 执行 Lua 脚本
  2. 查询 + 删除 一步做完
  3. 中间不可能卡住、不可能被打断、不可能插入其他命令

所以:

绝对不会出现:刚查完锁,就被别人抢走,然后删错锁的问题!

八、最直白总结(3 句话)

  1. 原来释放锁是两步(查、删),会被打断 → 出现删错锁的 BUG
  2. Lua 脚本把两步变成一步 → 原子性,绝对不被打断
  3. Redis 单线程执行 Lua → 绝对安全

九、一句话记忆

Lua 脚本 = 多条 Redis 命令合成一条,保证原子性,不被打断!

你现在是不是彻底懂了?

整个黑马点评分布式锁的终极方案就是:

  1. setnx + 过期时间 加锁
  2. Lua 脚本 释放锁(保证原子性)
  3. 解决:删错锁问题

全部评论

(0) 回帖
加载中...
话题 回帖