生成当天递增唯一的流水号的几种方式

说明:当开发中,如交易、文件传输过程中的文件名,可能需要我们使用一串唯一的数字来锁定这一条“交互记录”,即流水号。

本文介绍几种生成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重新开始)

生成当天递增唯一的流水号的几种方式_第1张图片

可在Redis中看到这两个值,即最后一次生成流水号的时间,以及生成的流水号

生成当天递增唯一的流水号的几种方式_第2张图片

方式二:存储过程

我们可以在数据库里维护一张表(rb_generate_serial_number),这张表里面的数据是最近一次生成的流水号时间(generate_date)以及流水号(last_number)。相当于把存到Redis中的那两个值放到数据库表中存储。如下:

在这里插入图片描述

然后写一个存储过程,当在DAO层去调用存储过程时,就生成一个新的流水号。存储过程如下:

CREATE DEFINER=`root`@`localhost` PROCEDURE `rb_generate_serial_number`()
BEGIN
  DECLARE currentSerialNumber INT;
  DECLARE lastCreateDate DATE;

  -- 从表中获取上次生成的流水号和生成的日期
  SELECT last_number, generate_date INTO currentSerialNumber, lastCreateDate FROM o_serial_number_log;

  -- 检查流水号是否为NULL,如果为NULL,则将其重置为1
  IF currentSerialNumber IS NULL THEN
    SET currentSerialNumber = 0;
  END IF;

  -- 检查日期是否为NULL,如果为NULL,则重置流水号为1并更新生成流水号的时间为今天
  IF lastCreateDate IS NULL THEN
    SET 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开始。

生成当天递增唯一的流水号的几种方式_第3张图片

数据库表同时更新;

生成当天递增唯一的流水号的几种方式_第4张图片

方式三:查询业务表

如果你的业务表中,已包含以上两个字段,则可以在生成流水号时,去查询业务表中最新的流水号,然后递增1作为新生成的流水号。

如果日期不是当天,则重置从1开始。

总结

生成唯一递增,且每日重置的流水号,关键就在于将上次生成流水号的信息存储出来,本次生成时再取出来做简单的判断。据此分出三种方式:

  • 存在Redis中,需要考虑Redis宕机的情况;

  • 存在数据库表中,需要额外写存储过程;

  • 从现有的数据库表中获取,需要在业务代码里写判断;

你可能感兴趣的:(数据库,java,mysql)