繁难适用!应用Redis轻松成功高并发全局ID生成器
我置信你会经常遇到要生成惟一 ID 的场景,比如标识每次恳求、生成一个订单编号、创立用户须要创立一个用户 ID。
UUID 确实是个好物品,生成的 ID 世界惟一,但是有两个致命毛病。
别急,今日我就给大家带来一个神器级的处置打算——Redis 散布式 ID 生成器!配合 SpringBoot3.0,让你的 ID 生成变得既繁难又高效。
散布式 ID 要满足什么要求
散布式 ID 生成器须要满足以下个性。
Redis 集群能保障高可用和高功能,为了节俭内存,ID 可以经常使用数字的方式,并且经过递增的方式来创立新的 ID。
防止重启数据失落,你还须要把 Redis AOF 耐久化开启。
好主意,在生成 ID 之后发送一条信息到 MQ 信息队列中,把值耐久化到 MySQL 中。
咱们可以经常使用 Redis String 数据类型来成功,key 用于辨别不同业务场景的 ID 生成器,value 存储 ID。
String 数据类型提供了INCR指令,它能把 key 中存储的数字加 1 并前往客户端。假设 key 不存在,那么 key 的 value 先被初始化成 0,再口头加 1 操作并前往给客户端。
Redis,作为一个高功能的内存数据库,天生就适宜处置高并发的场景。它的“复线程”模型更是让它在处置 ID 生成时瓮中之鳖。
Redis 的操作是原子性的,这就象征着在整个环节中,不会有任何的并发疑问出现,从而确保了 ID 的惟一性。
设计思绪如下图所示。
图 2-4
接上去,咱们联合 SpringBoot3.0 来打造一个弱小且易用的 Redis 散布式 ID 生成器。
首先,咱们须要在 SpringBoot 名目中引入 redis 的依赖。在pom.xml文件中添上这行代码:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
搞定依赖后,咱们得通知 SpringBoot 怎样衔接到 Redis。关上application.yml文件,填上 Redis 的服务地址和端口:
spring:application:name: redisredis:host: 127.0.0.1port: 6379password: magebytetimeout: 6000
万事俱备,只欠西风!接上去,咱们编写一个 ID 生成器工具类。这个工具类担任与 Redis 交互,生成惟一的 ID。这里咱们经常使用 Redis 的INCR命令,它能让 ID 自增,确保每次失掉的 ID 都是惟一的。
@Componentpublic class OrderIdGenerator implements InitializingBean {private final StringRedisTemplate redisTemplate;/*** 操作数据库 dao*/private final IdGeneratorMapper idGeneratorMapper;private static final String KEY = "counter:order";/*** 数据库中的 ID 值*/private String dbId;@Autowiredpublic OrderIdGenerator(StringRedisTemplate redisTemplate, IdGeneratorMapper idGeneratorMapper) {this.redisTemplate = redisTemplate;this.idGeneratorMapper = idGeneratorMapper;}public Long generateId(String key) {return redisTemplate.opsForValue().increment(key, 1);}@Overridepublic void afterPropertiesSet() throws Exception {// 从数据库查问最大 IDthis.dbId = idGeneratorMapper.getMaxID(KEY);Boolean hasKey = redisTemplate.hasKey(KEY);if (Boolean.TRUE.equals(hasKey)) {// key 存在,比拟 dbId 与 redisValue,取出最大值String redisValue = redisTemplate.opsForValue().get(KEY);String targetValue = max(this.dbId, redisValue);} else {
public String generateCustomId(String key, String prefix, String datePattern) {long sequence = redisTemplate.opsForValue().increment(key, 1);return String.format("%s-%s-%04d", prefix, new SimpleDateFormat(datePattern).format(new Date()), sequence);}
那详细怎样用呢?让咱们在业务代码中一探求竟!构想一下,在一个电商系统中,当一个新的订单如流星般划过天际,咱们迫不迭待地想要一个举世无双的 ID 来标志它时——很繁难,只需调用咱们的
generateCustomId
方法,传入订单关系的参数即可。
@Servicepublic class OrderService {private final RedisIdGenerator idGenerator;@Autowiredpublic OrderService(RedisIdGenerator idGenerator) {this.idGenerator = idativeIdGenerator;}public Order createOrder(OrderRequest request) {String orderId = idGenerator.generateCustomId("order:id", "ORD", "yyyyMMdd");Order order = new Order();order.setId(orderId);// 其余业务逻辑...return order;}}