利用 Redis + Redisson 分布式锁来生成全局唯一、线程安全的带日期前缀的流 ...

打印 上一主题 下一主题

主题 1661|帖子 1661|积分 4983

业务需求:创建一个流水号,

功能阐明:

1,格式:orgCode + yyyyMMdd + 4位序号,
2,天天重新从 0001 开始
3,利用 Redisson 保证并发下分布式唯一,
4,Redis 存储当天序列号
示例代码


  • Maven 依赖(假如还没加 Redisson):
  1. <dependency>
  2.     <groupId>org.redisson</groupId>
  3.     <artifactId>redisson</artifactId>
  4.     <version>3.17.7</version>
  5. </dependency>
复制代码

  • 设置 RedissonClient(示例单节点):
  1. @Configuration
  2. public class RedissonConfig {
  3.     @Bean
  4.     public RedissonClient redissonClient() {
  5.         Config config = new Config();
  6.         config.useSingleServer()
  7.               .setAddress("redis://127.0.0.1:6379") // 修改为你自己的 Redis 地址
  8.               .setDatabase(0);
  9.         return Redisson.create(config);
  10.     }
  11. }
复制代码

  • 流水号工具类:
  1. @Component
  2. public class SerialNumberGenerator {
  3.     @Autowired
  4.     private RedissonClient redissonClient;
  5.     private static final String SERIAL_KEY_PREFIX = "serial:";
  6.     public String generateSerialNumber(String orgCode) {
  7.         String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
  8.         String key = SERIAL_KEY_PREFIX + currentDate;
  9.         String lockKey = "lock:serial:" + currentDate;
  10.         RLock lock = redissonClient.getLock(lockKey);
  11.         try {
  12.             // 获取锁,最多等待5秒,锁自动释放时间为10秒
  13.             if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
  14.                 RAtomicLong counter = redissonClient.getAtomicLong(key);
  15.                 // 如果是新的一天,重置为0
  16.                 if (!counter.isExists()) {
  17.                     counter.set(0);
  18.                     // 设置过期时间为2天,避免key一直存在
  19.                     counter.expire(2, TimeUnit.DAYS);
  20.                 }
  21.                 long serial = counter.incrementAndGet();
  22.                 String formattedSerial = String.format("%04d", serial);
  23.                 return orgCode + currentDate + formattedSerial;
  24.             } else {
  25.                 throw new RuntimeException("生成流水号失败:获取锁超时");
  26.             }
  27.         } catch (InterruptedException e) {
  28.             throw new RuntimeException("生成流水号失败:线程中断", e);
  29.         } finally {
  30.             if (lock.isHeldByCurrentThread()) {
  31.                 lock.unlock();
  32.             }
  33.         }
  34.     }
  35. }
复制代码
为什么需要 Redis 分布式锁?
不加锁的问题
Redis 是高并发情况下的共享存储,多个实例并发 get + set 操作有可能导致并发写丢失或重复编号。
加锁保证:每次生成编号时只有一个线程在操作该 key 的值,从而保证原子性和唯一性


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

写过一篇

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表