【Redis 入门】Redis 锁与事务详解,新手零门槛上手

张开发
2026/4/16 10:09:19 15 分钟阅读

分享文章

【Redis 入门】Redis 锁与事务详解,新手零门槛上手
写在前面本文专为 Redis 初学者打造用最通俗的语言讲清楚 Redis 锁和事务看完就能用一、为什么需要 Redis 锁和事务1.1 一个简单的例子引入想象一个场景商品库存只剩 1 件 用户A和用户B 同时 点击购买如果没有任何保护机制用户A读到库存1 → 可以买 → 库存减1 → 库存0 ✅ 用户B读到库存1 → 可以买 → 库存减1 → 库存-1 ❌ 超卖了问题本质两个操作同时进行互相不知道对方的存在┌─────────────────────────────────────────┐ │ 没有锁的世界 │ │ │ │ 用户A ──读库存(1)──判断够──扣减──库存0 │ │ 用户B ──读库存(1)──判断够──扣减──库存-1 │ │ ↑ │ │ 同时读到1都以为能买 │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ 有锁的世界 │ │ │ │ 用户A ──拿到锁──读库存(1)──扣减──释放锁 │ │ 用户B ──等待──拿到锁──读库存(0)──不能买 │ │ ✅安全 │ └─────────────────────────────────────────┘1.2 锁和事务分别解决什么问题┌──────────────────────────────────────────────┐ │ │ │ Redis锁解决 并发竞争 问题 │ │ → 同一时间只能一个人操作 │ │ → 类比卫生间的门锁进去一个锁上门 │ │ │ │ Redis事务解决 操作打包 问题 │ │ → 多个命令要么一起执行要么都不执行 │ │ → 类比快递打包要寄就整个包裹一起寄 │ │ │ │ 两者结合 │ │ → 先用锁保证只有一个人操作 │ │ → 再用事务保证这个人的多个操作打包执行 │ │ │ └──────────────────────────────────────────────┘二、Redis 锁核心2.1 什么是 Redis 锁一句话定义利用 Redis 的命令特性实现 同一时间只有一个客户端能执行某段代码 的机制┌────────────────────────────────────────────────┐ │ │ │ Redis锁 本质上就是在Redis中 设置一个特殊的key │ │ │ │ 有这个key → 说明锁被占了 → 别人不能操作 │ │ 没有这个key → 说明锁是空的 → 可以抢锁操作 │ │ │ │ 类比理解 │ │ ┌─────────┐ │ │ │ 卫生间 │ │ │ │ 门锁Redis的key │ │ │ 锁上了key存在有人在用 │ │ │ 没锁key不存在可以进去 │ │ └─────────┘ │ │ │ └────────────────────────────────────────────────┘2.2 核心命令SETNXSETNXSETifNot eXists不存在时才设置# 基本语法 SETNX key value # 返回值 # 1 → 设置成功拿到锁了 # 0 → 设置失败锁被别人占了简单示例# 用户A 尝试加锁 127.0.0.1:6379 SETNX my_lock userA (integer) 1 # ✅ 返回1加锁成功 # 用户B 也尝试加锁 127.0.0.1:6379 SETNX my_lock userB (integer) 0 # ❌ 返回0锁被占了加锁失败 # 用户A 操作完毕释放锁 127.0.0.1:6379 DEL my_lock (integer) 1 # 锁释放了 # 此时用户B 再尝试 127.0.0.1:6379 SETNX my_lock userB (integer) 1 # ✅ 现在可以拿到锁了执行流程图 用户A Redis 用户B │ │ │ │──SETNX my_lock A──→ │ │ │←── 返回 1成功───── │ │ │ │ ←─SETNX my_lock B──│ │ │──── 返回 0失败────→│ │ 执行业务操作... │ │ 等待... │──DEL my_lock────────→│ │ │ │ ←─SETNX my_lock B──│ │ │──── 返回 1成功────→│2.3 ⚠️ 必须设置过期时间新手最常犯的错误只加锁不设过期时间 危险场景 用户A拿到锁 → 程序崩溃了/服务器宕机了 → 锁永远不会被释放 → 所有人都在等 → 系统瘫痪 死锁正确做法加锁时同时设置过期时间# ❌ 错误写法分两步不安全 SETNX my_lock userA # 第1步加锁 EXPIRE my_lock 10 # 第2步设过期时间 # 如果第1步成功后程序崩了第2步没执行 → 还是死锁 # ✅ 正确写法一条命令搞定原子操作 SET my_lock userA NX EX 10 # NX 不存在才设置等同于SETNX的效果 # EX 10 10秒后自动过期 # 一条命令 原子操作 不会出现加了锁但没设过期时间的情况参数说明 SET key value [NX] [EX seconds] │ │ │ │ │ │ │ │ │ └── 过期时间秒 │ │ │ └────────── 只在key不存在时设置 │ │ └─────────────── 锁的值标识谁加的锁 │ └──────────────────── 锁的名字 └───────────────────────── 命令2.4 释放锁的正确姿势核心原则谁加的锁谁来释放 误释放场景 时间线 0秒 用户A加锁过期时间10秒 ... 用户A执行业务业务比较慢 10秒 锁自动过期了 11秒 用户B拿到锁开始执行 12秒 用户A业务终于做完了执行DEL释放锁 → 但这时候释放的是用户B的锁❌ 用户A Redis 用户B │ │ │ │──SET lock A────→│ │ │ (EX 10) │ │ │ 业务处理中... │ │ │ ...太慢了... │ │ │ │ 10秒到锁自动过期 │ │ │ │ │ │←─SET lock B─────│ │ │ (成功拿到锁) │ │ │ │ 业务处理中... │──DEL lock────────→│ │ │ (以为删的是自己的) │ 锁被删了 │ │ │ │ 锁没了不安全了正确做法释放前先检查是不是自己的锁# 加锁时value设为唯一标识比如UUID SET my_lock uuid-abc-123 NX EX 10 # 释放锁时先检查再删除 # 伪代码逻辑 # if (GET my_lock uuid-abc-123) { ← 是我的锁 # DEL my_lock ← 才删除 # }Java 代码示例/** * Redis分布式锁 - 简单实现 * 适合初学者理解核心原理 */ public class SimpleRedisLock { private StringRedisTemplate redisTemplate; private String lockKey; private String lockValue; // 唯一标识区分是谁加的锁 public SimpleRedisLock(StringRedisTemplate redisTemplate, String lockKey) { this.redisTemplate redisTemplate; this.lockKey lockKey; // 用UUID作为唯一标识 this.lockValue UUID.randomUUID().toString(); } /** * 加锁 * param expireSeconds 过期时间秒 * return true加锁成功 false加锁失败 */ public boolean lock(long expireSeconds) { // SET key value NX EX seconds一条命令原子操作 Boolean result redisTemplate.opsForValue() .setIfAbsent(lockKey, lockValue, expireSeconds, TimeUnit.SECONDS); // setIfAbsent 就是 SETNX 的Java版本 return Boolean.TRUE.equals(result); } /** * 释放锁安全释放只删自己的 */ public void unlock() { // 先获取锁的值 String currentValue redisTemplate.opsForValue().get(lockKey); // 判断是不是自己加的锁 if (lockValue.equals(currentValue)) { // 是自己的锁才删除 redisTemplate.delete(lockKey); } // 不是自己的锁就不管避免误释放 } }使用方式/** * 模拟秒杀扣减库存 */ public String seckill(Long productId) { // 1. 创建锁对象 SimpleRedisLock lock new SimpleRedisLock( redisTemplate, lock:seckill: productId // 锁的key按商品区分 ); // 2. 尝试加锁10秒过期 boolean locked lock.lock(10); if (!locked) { // 没拿到锁说明别人在操作 return 系统繁忙请稍后再试; } try { // 3. 拿到锁了安全地执行业务 // 查库存 int stock getStock(productId); if (stock 0) { return 库存不足; } // 扣减库存 decreaseStock(productId); return 秒杀成功; } finally { // 4. 一定要在finally中释放锁 // 保证不管业务成功还是异常锁都能释放 lock.unlock(); } }2.5 Redis 锁知识总结┌──────────────────────────────────────────────────────┐ │ Redis锁 核心要点 │ ├──────────────────────────────────────────────────────┤ │ │ │ 1️⃣ 加锁命令SET key value NX EX seconds │ │ → NX保证互斥EX防止死锁 │ │ │ │ 2️⃣ 必须设过期时间 │ │ → 防止程序崩溃导致死锁 │ │ │ │ 3️⃣ value要唯一UUID │ │ → 释放锁时确认是自己的锁 │ │ │ │ 4️⃣ 释放锁要在finally中 │ │ → 保证一定能释放 │ │ │ │ 5️⃣ 先判断再释放 │ │ → 避免误删别人的锁 │ │ │ │ 记忆口诀 │ │ 加锁带过期value要唯一 │ │ 释放先判断finally不能忘 │ │ │ └──────────────────────────────────────────────────────┘三、Redis 事务核心3.1 什么是 Redis 事务一句话定义把多个 Redis 命令打包在一起一次性按顺序执行类比理解 快递打包寄件 没有事务散件 有事务打包 寄衣服 → 可能丢 ┌─────────┐ 寄裤子 → 可能丢 │ 衣服 │ 寄鞋子 → 可能丢 │ 裤子 │ → 整个包裹一起寄 │ 鞋子 │ └─────────┘ 要到就全到3.2 事务三大命令┌──────────────────────────────────────────────────┐ │ │ │ MULTI → 开始事务告诉Redis我要开始打包了 │ │ 命令1 → 入队先不执行放到队列里 │ │ 命令2 → 入队 │ │ 命令3 → 入队 │ │ EXEC → 执行事务告诉Redis打包好了一起执行 │ │ │ │ DISCARD → 取消事务不要了全部扔掉 │ │ │ └──────────────────────────────────────────────────┘完整示例# 场景转账 - A给B转100元 # A余额500 B余额200 127.0.0.1:6379 SET balance:A 500 OK 127.0.0.1:6379 SET balance:B 200 OK # 开始事务 127.0.0.1:6379 MULTI OK # 以下命令不会立即执行而是进入队列 127.0.0.1:6379(TX) DECRBY balance:A 100 # A减100 QUEUED # ← 注意返回QUEUED不是结果 127.0.0.1:6379(TX) INCRBY balance:B 100 # B加100 QUEUED # ← 还是QUEUED # 执行事务所有命令一起执行 127.0.0.1:6379(TX) EXEC 1) (integer) 400 # A的余额变成400 2) (integer) 300 # B的余额变成300 # ✅ 两个操作一起完成了执行流程 客户端 Redis服务器 │ │ │──── MULTI ─────────────→ │ 好的开始记录 │←──── OK ────────────────│ │ │ │──── DECRBY A 100 ──────→│ 命令队列[DECRBY A 100] │←──── QUEUED ────────────│ │ │ │──── INCRBY B 100 ──────→│ 命令队列[DECRBY A 100, INCRBY B 100] │←──── QUEUED ────────────│ │ │ │──── EXEC ──────────────→│ 开始按顺序执行队列中的所有命令 │ │ 执行 DECRBY A 100 → 400 │ │ 执行 INCRBY B 100 → 300 │←──── [400, 300] ────────│ 返回所有结果取消事务示例127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET name zhangsan QUEUED 127.0.0.1:6379(TX) SET age 18 QUEUED # 突然不想执行了取消 127.0.0.1:6379(TX) DISCARD OK # 事务已取消之前的命令全部丢弃 127.0.0.1:6379 GET name (nil) # 没有设置成功因为事务被取消了3.3 ⚠️ Redis 事务 vs MySQL 事务新手必看这是初学者最容易搞混的地方┌─────────────────────────────────────────────────────────┐ │ Redis事务 vs MySQL事务 对比 │ ├──────────────┬──────────────────┬────────────────────────┤ │ 特性 │ MySQL事务 │ Redis事务 │ ├──────────────┼──────────────────┼────────────────────────┤ │ 原子性 │ ✅ 严格支持 │ ⚠️ 部分支持 │ │ │ 全成功或全失败 │ 某条命令失败 │ │ │ │ 其他命令继续执行 │ ├──────────────┼──────────────────┼────────────────────────┤ │ 回滚 │ ✅ 支持回滚 │ ❌ 不支持回滚 │ │ │ 失败自动恢复 │ 失败了就失败了 │ │ │ (ROLLBACK) │ 没有ROLLBACK命令 │ ├──────────────┼──────────────────┼────────────────────────┤ │ 隔离性 │ ✅ 支持 │ ✅ 支持 │ │ │ 多种隔离级别 │ 命令按顺序执行 │ │ │ │ 中间不会被打断 │ ├──────────────┼──────────────────┼────────────────────────┤ │ 持久性 │ ✅ 写入磁盘 │ ⚠️ 看持久化配置 │ │ │ │ 默认可能丢数据 │ └──────────────┴──────────────────┴────────────────────────┘重点理解Redis 事务中某条命令失败其他命令照样执行# 示例事务中有一条命令执行失败 127.0.0.1:6379 SET name zhangsan OK 127.0.0.1:6379 SET age 18 OK 127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET name lisi # 正常命令 QUEUED 127.0.0.1:6379(TX) INCR name # ❌ 对字符串做加1操作会失败 QUEUED 127.0.0.1:6379(TX) SET age 20 # 正常命令 QUEUED 127.0.0.1:6379(TX) EXEC 1) OK # ✅ name设置成功 2) (error) ERR value is not an integer... # ❌ 这条失败了 3) OK # ✅ age设置成功没有回滚 127.0.0.1:6379 GET name lisi # ✅ 被修改了 127.0.0.1:6379 GET age 20 # ✅ 也被修改了⚠️ 关键记忆 MySQL事务一个失败 → 全部回滚全家一起回 Redis事务一个失败 → 其他继续各管各的 这是Redis事务最坑新手的地方 Redis事务更像是命令打包批量执行而不是严格的数据库事务3.4 两种错误情况区分┌───────────────────────────────────────────────────┐ │ Redis事务中的两种错误 │ ├─────────────────────┬─────────────────────────────┤ │ 编译期错误语法错误│ 运行期错误逻辑错误 │ ├─────────────────────┼─────────────────────────────┤ │ 命令写错了 │ 命令没写错 │ │ 比如: SETT name │ 但执行时类型不对 │ │ (SET写成SETT) │ 比如: INCR name │ │ │ (name是字符串不能加1) │ ├─────────────────────┼─────────────────────────────┤ │ 结果整个事务被丢弃 │ 结果只有这条失败 │ │ 所有命令都不执行 ✅ │ 其他命令正常执行 ⚠️ │ └─────────────────────┴─────────────────────────────┘# 编译期错误示例整个事务被丢弃 127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET name zhangsan QUEUED 127.0.0.1:6379(TX) SETT age 18 # ← 命令写错了 (error) ERR unknown command SETT # ← 直接报错不是QUEUED 127.0.0.1:6379(TX) SET email testqq.com QUEUED 127.0.0.1:6379(TX) EXEC (error) EXECABORT Transaction discarded # ← 整个事务被丢弃 # name和email都没设置3.5 WATCH 命令乐观锁WATCH可以实现类似 乐观锁 的效果在事务执行前监控某个 key# 场景A和B同时修改同一个值 # --- 窗口A --- 127.0.0.1:6379 WATCH balance # 监控balance OK 127.0.0.1:6379 GET balance 100 # 此时窗口B修改了balance见下方 127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) DECRBY balance 50 QUEUED 127.0.0.1:6379(TX) EXEC (nil) # ← 返回nil事务没有执行 # 因为balance在WATCH之后被别人改了 # --- 窗口B ---在A的MULTI之前执行 127.0.0.1:6379 SET balance 200 # B修改了balance OKWATCH 执行流程 窗口A Redis 窗口B │ │ │ │── WATCH balance ───────→│ 记录balance当前值100 │ │ │ │ │ │ ←── SET balance 200 ──│ │ │ balance变成200了 │ │ │ │ │── MULTI ───────────────→│ │ │── DECRBY balance 50 ──→│ 入队 │ │── EXEC ────────────────→│ │ │ │ 检查balance被改过了 │ │ │ WATCH的值100≠当前200 │ │←── (nil) ──────────────│ 事务取消不执行 │ 总结WATCH 执行前检查如果被别人改了就放弃事务3.6 Redis 事务知识总结┌──────────────────────────────────────────────────────┐ │ Redis事务 核心要点 │ ├──────────────────────────────────────────────────────┤ │ │ │ 1️⃣ 三个命令MULTI开始、EXEC执行、DISCARD取消│ │ │ │ 2️⃣ 命令入队不立即执行EXEC时才一起执行 │ │ │ │ 3️⃣ 不支持回滚不支持回滚不支持回滚 │ │ 重要的事情说三遍 │ │ │ │ 4️⃣ 语法错误 → 整个事务丢弃 │ │ 运行错误 → 只有出错的命令失败其他照常 │ │ │ │ 5️⃣ WATCH实现乐观锁被修改就放弃事务 │ │ │ │ 记忆口诀 │ │ MULTI开始EXEC提交命令入队先不执行 │ │ 不支持回滚要记牢WATCH监控搞乐观锁 │ │ │ └──────────────────────────────────────────────────────┘四、锁与事务结合实战4.1 应用场景┌───────────────────────────────────────────────────────┐ │ 锁 事务 典型应用场景 │ ├───────────────────────────────────────────────────────┤ │ │ │ 秒杀抢购 │ │ 锁保证同一时间只有一个请求在处理 │ │ 事务保证判断库存扣减库存打包执行 │ │ │ │ 接口防重复提交 │ │ 锁用户短时间内只能提交一次 │ │ 事务保证业务操作的完整性 │ │ │ │ 账户余额操作 │ │ 锁防止并发导致余额计算错误 │ │ 事务保证查余额扣余额记流水一起执行 │ │ │ └───────────────────────────────────────────────────────┘4.2 简单实战秒杀扣库存/** * 秒杀扣库存 - Redis锁 事务 * * 整体思路 * 1. 先用锁保证只有一个线程在操作 * 2. 在锁的保护下用事务打包执行扣库存操作 */ public String seckill(Long productId, Long userId) { String lockKey lock:seckill: productId; String lockValue UUID.randomUUID().toString(); String stockKey stock: productId; try { // 第1步加锁 Boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS); if (!Boolean.TRUE.equals(locked)) { return ❌ 系统繁忙请稍后再试; } // 第2步在锁的保护下检查库存 String stockStr redisTemplate.opsForValue().get(stockKey); int stock Integer.parseInt(stockStr); if (stock 0) { return ❌ 库存不足秒杀结束; } // 第3步扣减库存可以用事务 // 简单场景直接扣减即可 redisTemplate.opsForValue().decrement(stockKey); // 第4步记录购买信息 redisTemplate.opsForSet().add(purchased: productId, userId.toString()); return ✅ 秒杀成功; } finally { // 第5步释放锁安全释放 String currentValue redisTemplate.opsForValue().get(lockKey); if (lockValue.equals(currentValue)) { redisTemplate.delete(lockKey); } } }执行流程图 ┌──────────────────────────────────────────────────────────┐ │ 秒杀流程 │ │ │ │ 用户请求 ──→ 尝试加锁 ──→ 失败 ──→ 返回系统繁忙 │ │ │ │ │ ↓ 成功 │ │ 查询库存 │ │ │ │ │ ┌─────┴─────┐ │ │ ↓ ↓ │ │ 库存0 库存0 │ │ │ │ │ │ ↓ ↓ │ │ 扣减库存 返回库存不足 │ │ 记录购买 │ │ │ │ │ ↓ │ │ 返回秒杀成功 │ │ │ │ │ ↓ │ │ 释放锁finally中执行保证一定释放 │ │ │ └──────────────────────────────────────────────────────────┘4.3 锁和事务的顺序新手必看⚠️ 正确顺序先加锁 → 再开事务 → 执行业务 → 提交事务 → 释放锁 ┌────────────────────────────────────────┐ │ ✅ 正确顺序 │ │ │ │ 1. 加锁 ← 最外层 │ │ 2. 开启事务 ← 锁的保护内部 │ │ 3. 执行操作 │ │ 4. 提交事务 │ │ 5. 释放锁 ← 最后释放 │ │ │ │ 类比先锁门 → 在屋里干活 → 干完开门 │ └────────────────────────────────────────┘ ┌────────────────────────────────────────┐ │ ❌ 错误顺序 │ │ │ │ 1. 开启事务 │ │ 2. 加锁 ← ❌ 反了 │ │ 3. 执行操作 │ │ 4. 释放锁 │ │ 5. 提交事务 │ │ │ │ 问题锁释放后事务还没提交 │ │ → 别人可能在你事务提交前就读到旧数据 │ │ → 并发问题没有真正解决 │ └────────────────────────────────────────┘五、新手避坑总结5.1 Redis 锁常见坑┌─────────────────────────────────────────────────────────┐ │ Redis锁 新手四大坑 │ ├────┬────────────────────┬───────────────────────────────┤ │ 编号│ 坑 │ 解决方案 │ ├────┼────────────────────┼───────────────────────────────┤ │ 1 │ 忘记设过期时间 │ 用 SET key val NX EX 一条搞定 │ │ │ → 死锁 │ │ ├────┼────────────────────┼───────────────────────────────┤ │ 2 │ 误删别人的锁 │ value用UUID │ │ │ → 锁失效 │ 释放前先判断是不是自己的 │ ├────┼────────────────────┼───────────────────────────────┤ │ 3 │ 过期时间设太短 │ 根据业务评估时间 │ │ │ → 业务没做完锁就没了 │ 进阶用Redisson自动续期 │ ├────┼────────────────────┼───────────────────────────────┤ │ 4 │ 没在finally释放锁 │ 永远在finally中释放 │ │ │ → 异常时锁不释放 │ │ └────┴────────────────────┴───────────────────────────────┘5.2 Redis 事务常见坑┌─────────────────────────────────────────────────────────┐ │ Redis事务 新手三大坑 │ ├────┬────────────────────┬───────────────────────────────┤ │ 编号│ 坑 │ 正确认知 │ ├────┼────────────────────┼───────────────────────────────┤ │ 1 │ 以为有回滚 │ Redis事务没有回滚 │ │ │ → 出错后等回滚 │ 失败的命令就是失败了 │ │ │ 白等 │ 其他命令照样执行 │ ├────┼────────────────────┼───────────────────────────────┤ │ 2 │ MULTI后以为命令 │ MULTI后命令只是入队QUEUED │ │ │ 立即执行 │ 只有EXEC后才真正执行 │ ├────┼────────────────────┼───────────────────────────────┤ │ 3 │ 以为和MySQL事务一样 │ Redis事务≈批量执行 │ │ │ → 依赖它做数据一致性 │ 严格一致性还是要靠MySQL │ └────┴────────────────────┴───────────────────────────────┘5.3 一图总结┌──────────────────────────────────────────────────────────────┐ │ │ │ Redis锁 事务 全景图 │ │ │ │ ┌─────────┐ ┌─────────────┐ │ │ │ Redis锁 │ │ Redis事务 │ │ │ │ │ │ │ │ │ │ 解决问题│ │ 解决问题 │ │ │ │ 并发竞争 │ │ 操作打包 │ │ │ │ │ │ │ │ │ │ 核心命令│ │ 核心命令 │ │ │ │ SET NX EX│ │ MULTI │ │ │ │ DEL │ │ EXEC │ │ │ │ │ │ DISCARD │ │ │ │ 注意 │ │ │ │ │ │ 过期时间 │ │ 注意 │ │ │ │ 安全释放 │ │ 不支持回滚 │ │ │ └────┬────┘ └──────┬──────┘ │ │ │ │ │ │ └──────┬──────────────┘ │ │ │ │ │ ↓ │ │ ┌───────────────┐ │ │ │ 结合使用 │ │ │ │ │ │ │ │ 先加锁 │ │ │ │ 再开事务 │ │ │ │ 执行业务 │ │ │ │ 提交事务 │ │ │ │ 最后释放锁 │ │ │ │ │ │ │ │ 应用秒杀 │ │ │ │ 防重复 │ │ │ │ 转账 │ │ │ └───────────────┘ │ │ │ │ 记忆总结 │ │ 锁管谁能操作并发控制 │ │ 事务管怎么操作批量执行 │ │ 先锁后事务finally释放锁 │ │ │ └──────────────────────────────────────────────────────────────┘六、进阶方向学完本文的基础内容后可以继续深入当前水平 进阶方向 ──────── ──────── ✅ SETNX基础锁 → Redisson分布式锁自动续期、可重入 ✅ 单机Redis锁 → RedLock算法Redis集群下的锁 ✅ 简单Redis事务 → Lua脚本真正的原子操作 ✅ 手动释放锁 → Lua脚本实现判断释放原子操作 ✅ 基础并发场景 → 高并发场景下的锁优化策略总结一句话Redis 锁解决 谁能用 的问题事务解决 打包执行 的问题两者结合就是先锁门再干活最后开门记住 加锁带过期、释放先判断、事务不回滚 这三个核心就够入门了

更多文章