流水號的生成(日期+業務碼+自增序列)


項目開發時,使用了兩套數據庫,開發環境和上線環境,數據庫表中大多採用了自增主鍵,
比方:

id int unsigned primary key auto_increment,

但往往會碰到一些問題。比方:
開發環境中,使用爬蟲抓取一些數據,建立索引。再把數據遷移到上線環境,會導致索引中的id和
上線環境數據庫中id對不上,所以決定使用字符串作為主鍵。

那么問題來了,怎樣生成唯一的序列號?
格式依照:yyyyMMdd+兩位業務碼+10位的自增序列。

比方20150101**99**0000000001。

思路:
獲得日期非常easy;
業務碼是調用服務傳入的參數;
使用Redis來實現10位的自增序列的保存和自增,使用serial.number:{日期}的格式來保存某一天的自增序列的值;

主要代碼例如以下:

public interface SerialNumberService {
    /** * 序列號自增序列 */
    String SERIAL_NUMBER = "serial.number:";

    /** * 依據兩位業務碼字符串,生成一個流水號,格式依照:<br/> * yyyyMMdd{bizCode}{10位的自增序列號} * * @param bizCode * 兩位,00-99 * @return 20位的序列號 * @throws ServiceException */
    String generate(String bizCode) throws ServiceException;

    //事實上,應該對bizCode做白名單驗證,以免惡意偽造
    default boolean isLegal(String bizCode) {
        if (bizCode == null || bizCode.length() != 2) {
            throw new RuntimeException("bizCode: " + bizCode + "異常");
        }
        if (Character.isDigit(bizCode.charAt(0))
                && Character.isDigit(bizCode.charAt(1)))
            return true;
        return false;
    }
}

@Service
public class SerialNumberServiceImpl implements SerialNumberService {
    @Resource
    private RedisDao redisDao;

    @Override
    public String generate(String bizCode) throws ServiceException {
        /** 檢查業務碼 */
        boolean isLegal = isLegal(bizCode);
        if (!isLegal) {
            throw new ServiceException("bizCode參數不合法");
        }
        /** 獲取今天的日期:yyyyMMdd */
        String date = TimeUtil.getToday();
        /** 構造redis的key */
        String key = SERIAL_NUMBER + date;
        /** 自增 */
        long sequence = redisDao.incr(key);
        String seq = StringUtil.getSequence(sequence);
        StringBuilder sb = new StringBuilder();
        sb.append(date).append(bizCode).append(seq);
        String serial = sb.toString();
        return serial;
    }
}

public class TimeUtil {
    private TimeUtil() {
    }

    /** * 獲取今日日期 * * @return */
    public static String getToday() {
        return "20150101";
    }

}

public class StringUtil {
    private StringUtil() {

    }

    static final int DEFAULT_LENGTH = 10;

    /** * 得到10位的序列號,長度不足10位,前面補0 * * @param seq * @return */
    public static String getSequence(long seq) {
        String str = String.valueOf(seq);
        int len = str.length();
        if (len >= DEFAULT_LENGTH) {// 取決於業務規模,應該不會到達10
            return str;
        }
        int rest = DEFAULT_LENGTH - len;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < rest; i++) {
            sb.append('0');
        }
        sb.append(str);
        return sb.toString();
    }

}

僅僅聲明了RedisDao接口,能夠使用Jedisclient來實現。

public interface RedisDao {
    String get(String key);

    /** * 自增,+1,返回添加后的值 * * @param key * @return */
    long incr(String key);
}

這樣Redis里面就存儲了每天產生的最大序列號。
能夠依據日期、業務碼等統計相關信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM