业务需求:创建一个流水号,
功能说明:
1,格式:orgCode + yyyyMMdd + 4位序号,
2,每天重新从 0001 开始
3,使用 Redisson 保证并发下分布式唯一,
4,Redis 存储当天序列号
示例代码
- Maven 依赖(如果还没加 Redisson):
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.17.7</version>
</dependency>
- 配置 RedissonClient(示例单节点):
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379") // 修改为你自己的 Redis 地址.setDatabase(0);return Redisson.create(config);}
}
- 流水号工具类:
@Component
public class SerialNumberGenerator {@Autowiredprivate RedissonClient redissonClient;private static final String SERIAL_KEY_PREFIX = "serial:";public String generateSerialNumber(String orgCode) {String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());String key = SERIAL_KEY_PREFIX + currentDate;String lockKey = "lock:serial:" + currentDate;RLock lock = redissonClient.getLock(lockKey);try {// 获取锁,最多等待5秒,锁自动释放时间为10秒if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {RAtomicLong counter = redissonClient.getAtomicLong(key);// 如果是新的一天,重置为0if (!counter.isExists()) {counter.set(0);// 设置过期时间为2天,避免key一直存在counter.expire(2, TimeUnit.DAYS);}long serial = counter.incrementAndGet();String formattedSerial = String.format("%04d", serial);return orgCode + currentDate + formattedSerial;} else {throw new RuntimeException("生成流水号失败:获取锁超时");}} catch (InterruptedException e) {throw new RuntimeException("生成流水号失败:线程中断", e);} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}}
}
为什么需要 Redis 分布式锁?
不加锁的问题:
Redis 是高并发环境下的共享存储,多个实例并发 get + set 操作有可能导致并发写丢失或重复编号。
加锁保证:每次生成编号时只有一个线程在操作该 key 的值,从而保证原子性和唯一性