简单实用,利用redis轻松实现高并发全局ID生成器

Redis作为高性能的KV数据库,并且操作还是原子性的,所以用来做支持高并发的发号器十分合适。

本文给大家介绍3种常见的全局ID生成方式。

1,全局递增ID

目标:一直递增的全局ID。

/**
 * 一直递增的全局id
 *
 * @param redisTemplate redis客户端对象
 * @param busId         业务id,可以按需配置
 * @param step          步长,即每次递增的间隔
 */
public static String getNo(RedisTemplate<String, Object> redisTemplate, String busId, int step) {
  //保存redis中的key,注意不要重复
  String redisKey = "uniqueNo_";
  //利用increment即redis原生incrBy命令的原子性特性生成递增的序列号
  Long increment = redisTemplate.opsForValue().increment(redisKey, step);
  if (increment == null) {
    throw new RuntimeException("redis命令执行失败");
  }
  //业务id+递增id,如果需要纯数字,去掉业务id即可
  return busId + increment;
}

2,以天为分割的全局ID

目标:生成格式为 yyyyMMdd + 递增序列号的全局ID。

/**
 * 以天为间隔的递增序列号
 * @param redisTemplate redis客户端对象
 * @param busId 业务id,可以按需配置
 * @param step 步长,即每次递增的间隔
*/
public static String getNo(RedisTemplate<String, Object> redisTemplate, String busId, int step) {
  //当天日期,比如20221226
  String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
  //保存redis中的key,注意不要重复
  String redisKey = "uniqueNo_" + date;
  //利用increment即redis原生incrBy命令的原子性特性生成递增的序列号
  Long increment = redisTemplate.opsForValue().increment(redisKey, step);
  if (increment == null) {
    throw new RuntimeException("redis命令执行失败");
  }
  if (step == increment.intValue()) {
    //首次执行时,给redisKey设置ttl,第二天这个key就可以被redis自动删除
    redisTemplate.expire(redisKey, 25, TimeUnit.HOURS);
  }
  //组合  20221226 + 业务id + 0001(可以根据需要自由调整序列号的长度)
  return date + busId + String.format("%04d", increment);
}

3,批量获取ID

有时我们需要批量的获取递增ID,比如给一批订单号设置ID。

/**
 * 批量获取id
 *
 * @param redisTemplate redis客户端对象
 * @param busId         业务id,可以按需配置
 * @param size          获取的id个数,与步长类似
 */
public static List<String> getNoByGroup(RedisTemplate<String, Object> redisTemplate, String busId, int size) {
  //保存redis中的key,注意不要重复
  String redisKey = "uniqueNo_group";
  //设置步长为size,相当于一次性申请size个id
  Long increment = redisTemplate.opsForValue().increment(redisKey, size);
  if (increment == null) {
    throw new RuntimeException("redis命令执行失败");
  }
  long begin = increment - Long.parseLong(size + "");
  List<String> rs = new ArrayList<>();
  for (long i = begin + 1; i <= increment; i++) {
    rs.add(busId + i);
  }
  return rs;
}

总结

无论我们需要什么格式的ID,其实只要我们把握住其中的核心:incrBy命令,根据其原子性的特性,就可以生成我们需要的全局ID。

但是需要注意的是,虽然incrBy命令是原子性的,但是通过组合键进行组合时,其实是破坏了这种原子性。如果有特殊的ID格式要求,务必要进行充分的测试。

我是@程序员拾山,全网同名,感谢您的点赞和关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员拾山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值