使用Redisson实现同一业务类型串行执行的分布式锁方案,解决并发问题

你要的是 "同一业务类型(bussType)串行执行" 的效果 ------ 即同一个 bussType 只能被一个线程处理,上一个线程执行完(释放锁),下一个线程才能进入。这种场景用 Redisson 的分布式锁 最合适,它支持细粒度锁(按 bussType 分锁),还能避免死锁、自动续期,比原生 Redis 锁更稳定。

以下是 基于 Redisson 的 "单 bussType 串行执行" 完整实现,直接替换原代码即可,兼顾并发安全和易用性:

核心思路

锁粒度:按 bussType 生成独立锁(比如 code:lock:order、code:lock:user),不同业务类型互不影响(并行执行),同一业务类型串行执行。

锁特性:用 Redisson 的 RLock,支持自动重试、超时释放、自动续期(避免长事务导致锁过期)。

执行逻辑:线程先拿对应 bussType 的锁 → 拿到锁后执行 "查 - 算 - 更" → 执行完释放锁 → 下一个线程竞争锁。

步骤 1:引入 Redisson 依赖(以 Spring Boot 为例)

xml

<!-- Redisson 核心依赖 -->

XML 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.3</version> <!-- 推荐用稳定版,和 Spring Boot 版本兼容 -->
</dependency>

步骤 2:配置 Redisson(application.yml)

复制代码
yaml
spring:
  redis:
    host: 127.0.0.1 # 你的 Redis 地址
    port: 6379
    password: #  Redis 密码(无则留空)
    database: 0

redisson:
  singleServerConfig:
    address: redis://${spring.redis.host}:${spring.redis.port}
    password: ${spring.redis.password}
    database: ${spring.redis.database}
    connectionMinimumIdleSize: 10 # 最小空闲连接数
    connectionPoolSize: 64 # 连接池大小
    idleConnectionTimeout: 10000 # 空闲连接超时时间
    connectTimeout: 10000 # 连接超时时间
    timeout: 3000 # 命令执行超时时间

步骤 3:改造 Service 方法(核心代码)

java 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@Service
public class SysCodeServiceImpl extends ServiceImpl<SysCodeConfMapper, SysCodeConfEntity> implements SysCodeService {

    @Autowired
    private RedissonClient redissonClient;

    // 锁前缀:避免和其他 Redis 锁冲突
    private static final String LOCK_PREFIX = "sys_code:lock:";

    // 锁等待时间:5秒(线程最多等5秒拿锁,超时返回失败)
    private static final long LOCK_WAIT_TIME = 5;

    // 锁自动释放时间:30秒(防止线程异常导致锁不释放)
    private static final long LOCK_LEASE_TIME = 30;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW) // 独立事务,减少锁持有时间
    public String getCodeByType(String bussType) {
        // 1. 生成当前业务类型的专属锁(细粒度锁,不影响其他 bussType)
        RLock lock = redissonClient.getLock(LOCK_PREFIX + bussType);

        try {
            // 2. 尝试获取锁:最多等5秒,拿到锁后30秒自动释放(支持自动续期)
            boolean isLocked = lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS);
            if (!isLocked) {
                log.error("获取编码锁失败,业务类型:{}(当前并发过高,请稍后重试)", bussType);
                throw new RuntimeException("编码生成繁忙,请稍后重试");
            }

            // 3. 拿到锁后,执行核心逻辑(此时同一 bussType 只有当前线程在执行)
            SysCodeConfEntity sysCodeConfEntity = baseMapper.selectOne(
                Wrappers.lambdaQuery(SysCodeConfEntity.class).eq(SysCodeConfEntity::getBussType, bussType)
            );
            if (sysCodeConfEntity == null) {
                log.warn("业务类型{}未配置编码规则", bussType);
                return null;
            }

            // 4. 生成新编码 + 更新数据库(串行执行,无并发冲突)
            String newCode = CodeUtil.generateNewCode(sysCodeConfEntity);
            baseMapper.updateById(sysCodeConfEntity);

            return newCode;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复线程中断状态
            log.error("编码生成被中断,业务类型:{}", bussType, e);
            return null;
        } finally {
            // 5. 释放锁(必须在 finally 中执行,确保锁一定释放)
            if (lock.isHeldByCurrentThread()) { // 防止未拿到锁却尝试释放
                lock.unlock();
            }
        }
    }
}

关键特性说明(为什么用 Redisson 而不是原生 Redis 锁?)

自动续期:如果事务执行时间超过 LOCK_LEASE_TIME(30 秒),Redisson 会自动给锁续期(默认每 10 秒续一次),避免锁过期导致并发问题。

非阻塞获取锁:tryLock 方法会在指定时间内尝试获取锁,超时返回失败,不会导致线程一直阻塞。

细粒度锁:每个 bussType 对应一个独立的锁,比如 code:lock:order 和 code:lock:user 是两个不同的锁,不同业务类型可以并行执行,不会全局串行(提升性能)。

死锁防护:锁有超时时间,即使线程异常崩溃,Redis 也会在超时后自动释放锁,避免死锁。

相关推荐
哈哈哈笑什么5 小时前
蜜雪冰城1分钱奶茶秒杀活动下,使用分片锁替代分布式锁去做秒杀系统
redis·分布式·后端
哈哈哈笑什么6 小时前
高并发分布式Springcloud系统下,使用RabbitMQ实现订单支付完整闭环的实现方案(反向撤销+重试+补偿)
分布式·spring cloud·rabbitmq
哈哈哈笑什么7 小时前
分布式高并发Springcloud系统下的数据图同步断点续传方案【订单/商品/用户等】
分布式·后端·spring cloud
LDG_AGI7 小时前
【推荐系统】深度学习训练框架(十三):模型输入——《特征索引》与《特征向量》的边界
人工智能·pytorch·分布式·深度学习·算法·机器学习
回家路上绕了弯8 小时前
多线程开发最佳实践:从安全到高效的进阶指南
分布式·后端
少许极端9 小时前
Redis入门指南:从零到分布式缓存(一)
redis·分布式·缓存·微服务
爬山算法9 小时前
Redis(161)如何使用Redis实现分布式锁?
数据库·redis·分布式
边缘计算社区9 小时前
云边协同推理再突破:新型分布式解码框架吞吐量提升近 10%
分布式
大猫子的技术日记10 小时前
[后端杂货铺]深入理解分布式事务与锁:从隔离级别到传播行为
分布式·后端·事务