当前位置: 首页 > 科技观察

简单实用!使用Redis轻松实现高并发的全局ID生成器

时间:2023-03-20 19:34:40 科技观察

Redis是一个高性能的KV数据库,操作仍然是原子的,非常适合作为高并发的发布器。本文介绍三种常见的全局ID生成方式。1.全局增量ID目标:一个始终递增的全局ID。/***全局id一直递增**@paramredisTemplateredis客户端对象*@parambusId业务id,可按需配置*@paramstep步长,即每次递增的间隔*/publicstaticStringgetNo(RedisTemplateredisTemplate,StringbusId,intstep){//将key保存在redis中,注意不要重复StringredisKey="uniqueNo_";//使用increment,即redis原生incrBy命令的原子特性,生成一个增量序列号longincrement=redisTemplate.opsForValue().increment(redisKey,step);if(increment==null){thrownewRuntimeException("redis命令执行失败");}//Businessid+incrementid,如果需要纯数字,去掉businessid可以returnbusId+increment;}2.globalID目标除以天数:生成一个globalID,格式为yyyyMMdd+incrementedserialnumber./***以天为间隔的增量序号*@paramredisTemplateredis客户端对象*@parambusId业务id,可按需配置*@paramstep步长,即每次增量的间隔*/publicstaticStringgetNo(RedisTemplateredisTemplate,StringbusId,intstep){//日期,比如20221226Stringdate=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));//将数据保存在rediskey中,注意不要重复StringredisKey="uniqueNo_"+date;//使用increment,redis原生incrBy命令的原子特性,生成一个增量序列号longincrement=redisTemplate.opsForValue().increment(redisKey,step);if(increment==null){thrownewRuntimeException("redis命令执行失败");}if(step==increment.intValue()){//第一次执行时,为redisKey设置ttl,key第二天可以用redis自动删除redisTemplate.expire(redisKey,25,TimeUnit.HOURS);}//组合20221226+businessid+0001(可以根据需要自由调整序列号的长度)returndate+busId+String.format("%04d",increment);}3.批量获取ID有时候我们需要批量获取增量ID,比如为一批订单号设置ID。/***批量获取ids**@paramredisTemplateredis客户端对象*@parambusId业务id,可根据需要配置*@paramsize获取id的个数,类似步长*/publicstaticListgetNoByGroup(RedisTemplateredisTemplate,StringbusId,intsize){//将key保存在redis中,注意不要重复StringredisKey="uniqueNo_group";//设置步长为size,相当于一次性申请sizeidlongincrement=redisTemplate.opsForValue().increment(redisKey,size);if(increment==null){thrownewRuntimeException("redis命令执行失败");}longbegin=increment-Long.parseLong(size+"");列表<字符串>rs=newArrayList<>();for(longi=begin+1;i<=increment;i++){rs.add(busId+i);}returnrs;}总结一下我们需要什么格式的ID,其实我们只要抓住核心:incrBy命令,根据它的原子特性,就可以生成我们需要的全局ID。不过需要注意的是,incrBy命令虽然是原子性的,但是在用组合键组合的时候实际上破坏了原子性。如果有特殊的ID格式要求,一定要进行充分的测试。