说明:当开发中,如交易、文件传输过程中的文件名,可能需要我们使用一串唯一的数字来锁定这一条“交互记录”,即流水号。
本文介绍几种生成6位递增唯一,且每日重置的流水号的方式。
方式一:使用Redis
我们可以将上次生成流水号的日期,以及生成的流水号存入到Redis中,需要生成流水号时去Redis中将这两个值取出来做判断。
-
如果日期不是今天,则从1开始,重新生成;
-
如果日期是今天,则将流水号的值递增1,返回;
代码如下:
(generateSerialNumber(),生成流水号方法)
private static final String REDIS_KEY_PREFIX = "serialNumber:";private static final String LAST_GENERATED_DATE_KEY = REDIS_KEY_PREFIX + "lastGeneratedDate";private static final String SERIAL_NUMBER_KEY = REDIS_KEY_PREFIX + "now";public synchronized String generateSerialNumber() {// 获取当前日期String today = LocalDate.now().toString();// 如果Redis中没有日期数据,或者Redis中的日期和当前日期不一致if (!today.equals(redisTemplate.opsForValue().get(LAST_GENERATED_DATE_KEY))) {redisTemplate.opsForValue().set(LAST_GENERATED_DATE_KEY, today);redisTemplate.opsForValue().set(SERIAL_NUMBER_KEY, "0");}// 流水号自增1,并格式化后返回long serialNumber = redisTemplate.opsForValue().increment(SERIAL_NUMBER_KEY,1);return String.format("%06d", serialNumber);}
(演示)
public void generate(){for (int i = 0; i < 10; i++) {System.out.println(generateSerialNumber());}}
(只要是同一天,流水号就递增1返回,不是同一天则重置,从1重新开始)
可在Redis中看到这两个值,即最后一次生成流水号的时间,以及生成的流水号
方式二:存储过程
我们可以在数据库里维护一张表(rb_generate_serial_number),这张表里面的数据是最近一次生成的流水号时间(generate_date)以及流水号(last_number)。相当于把存到Redis中的那两个值放到数据库表中存储。如下:
然后写一个存储过程,当在DAO层去调用存储过程时,就生成一个新的流水号。存储过程如下:
CREATE DEFINER=`root`@`localhost` PROCEDURE `rb_generate_serial_number`()
BEGINDECLARE currentSerialNumber INT;DECLARE lastCreateDate DATE;-- 从表中获取上次生成的流水号和生成的日期SELECT last_number, generate_date INTO currentSerialNumber, lastCreateDate FROM o_serial_number_log;-- 检查流水号是否为NULL,如果为NULL,则将其重置为1IF currentSerialNumber IS NULL THENSET currentSerialNumber = 0;END IF;-- 检查日期是否为NULL,如果为NULL,则重置流水号为1并更新生成流水号的时间为今天IF lastCreateDate IS NULL THENSET currentSerialNumber = 0;SET lastCreateDate = CURDATE();END IF;-- 检查生成流水号的日期是否为今天IF lastCreateDate = CURDATE() THEN-- 如果日期是今天,则递增流水号SET currentSerialNumber = currentSerialNumber + 1;ELSE-- 如果日期不是今天,则重置流水号为1并更新生成流水号的时间为今天SET currentSerialNumber = 1;SET lastCreateDate = CURDATE();END IF;-- 更新数据库中的流水号和日期UPDATE o_serial_number_log SET last_number = currentSerialNumber, generate_date = lastCreateDate;-- 返回6位流水号SELECT LPAD(currentSerialNumber, 6, '0') AS o_serial_number_log;
END
在代码中写一个Mapper方法,xml里面直接调用这个存储过程,如下:
<select id="generateSerialNumber" resultType="java.lang.String">call rb_generate_serial_number()</select>
在浏览器中测试,访问该接口,返回流水号的值。因为数据库里面记录的时间不是当天,则从1开始。
数据库表同时更新;
方式三:查询业务表
如果你的业务表中,已包含以上两个字段,则可以在生成流水号时,去查询业务表中最新的流水号,然后递增1作为新生成的流水号。
如果日期不是当天,则重置从1开始。
总结
生成唯一递增,且每日重置的流水号,关键就在于将上次生成流水号的信息存储出来,本次生成时再取出来做简单的判断。据此分出三种方式:
-
存在Redis中,需要考虑Redis宕机的情况;
-
存在数据库表中,需要额外写存储过程;
-
从现有的数据库表中获取,需要在业务代码里写判断;