业务需求:创建一个流水号,
功能阐明:
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 {
- @Bean
- public 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 {
- @Autowired
- private 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);
- // 如果是新的一天,重置为0
- if (!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 的值,从而保证原子性和唯一性
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |