就这?分布式 ID 发号器实战 (3)

使用 RedisAtomicLong 封装一个基础的 redis 自增序列工具类

// 只封装了部分方法,还可以扩展 @Service public class RedisService { @Autowired RedisTemplate<String, Object> redisTemplate; /** * 获取链接工厂 */ public RedisConnectionFactory getConnectionFactory() { return redisTemplate.getConnectionFactory(); } /** * 自增数 * @param key * @return */ public long increment(String key) { RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, getConnectionFactory()); return redisAtomicLong.incrementAndGet(); } /** * 自增数(带过期时间) * @param key * @param time * @param timeUnit * @return */ public long increment(String key, long time, TimeUnit timeUnit) { RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, getConnectionFactory()); redisAtomicLong.expire(time, timeUnit); return redisAtomicLong.incrementAndGet(); } /** * 自增数(带过期时间) * @param key * @param expireAt * @return */ public long increment(String key, Instant expireAt) { RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, getConnectionFactory()); redisAtomicLong.expireAt(expireAt); return redisAtomicLong.incrementAndGet(); } /** * 自增数(带过期时间和步长) * @param key * @param increment * @param time * @param timeUnit * @return */ public long increment(String key, int increment, long time, TimeUnit timeUnit) { RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, getConnectionFactory()); redisAtomicLong.expire(time, timeUnit); return redisAtomicLong.incrementAndGet(); } }

根据业务需求编写发号器方法

@Service public class IdGeneratorService { @Autowired RedisService redisService; /** * 生成id(每日重置自增序列) * 格式:日期 + 6位自增数 * 如:20210804000001 * @param key * @param length * @return */ public String generateId(String key, Integer length) { long num = redisService.increment(key, getEndTime()); String id = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + String.format("%0" + length + "d", num); return id; } /** * 获取当天的结束时间 */ public Instant getEndTime() { LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX); return endTime.toInstant(ZoneOffset.ofHours(8)); } }

由于业务需求,需要每天都重置自增序列,所以这里以每天结束时间为过期时间,这样第二天又会从1开始。

测试一下

@SpringBootTest class IdGeneratorServiceTest { @Test void generateIdTest() { String code = idGeneratorService.generateId("orderId", 6); System.out.println(code); } } // 输出:20210804000001

6位自增序列每天可以生成将近100w个编码,对于大多数公司,已经足够了。

经过本地环境测试,开启10个线程,1秒内每个线程10000个请求,没有丝毫压力。

如果觉得有些场景下连续的编号会泄漏公司的数据,比如订单量,那么可以设置随机增长步长,这样就看不出具体订单量了。但是会影响生成的编码数量,可以根据实际情况调整自增序列的位数。

img

总结

没有最好的,只有最合适的。在实际工作中往往都是这样,需要根据实际业务需求来选择最合适的方案。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zysjyj.html