Java之流水號生成器實現


  

  參考:https://www.jianshu.com/p/331b872e9c8f

 

  1.建立一張存放的表

  

CREATE TABLE `sys_serial_number` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`module_name` varchar(50) DEFAULT NULL COMMENT '模塊名稱',
`module_code` varchar(50) DEFAULT NULL COMMENT '模塊編碼(唯一的)',
`config_templet` varchar(50) DEFAULT NULL COMMENT '訂單前綴',
`max_serial` varchar(32) DEFAULT NULL COMMENT '存放當前序列號的值',
`pre_max_num` varchar(32) DEFAULT NULL COMMENT '預生成序列號存放到緩存的個數',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='序列自增長表';

 

package ch.service.sys;

import ch.common.util.CacheUtils;
import ch.dao.sys.SerialNumDao;
import ch.entity.sys.SystemSerialNumberEntity;
import ch.util.DateUtils;
import ch.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Description:
 *
 * @author cy
 * @date 2019年05月07日 13:23
 * version 1.0
 */
@Service
public class SerialNumberServiceImpl implements SerialNumService {

    @Autowired
    private SerialNumDao serialNumDao;

    /** 日期格式 */
    private String pattern = "yyyyMMddHHmmss";

    /** 生成器鎖 */
    private final ReentrantLock lock = new ReentrantLock();

    /** 流水號格式化器 */
    private DecimalFormat format = new DecimalFormat("00");

    /** 預生成鎖 */
    private final ReentrantLock prepareLock = new ReentrantLock();

    /** 最小值 */
    private int min = 0;

    /** 最大值 */
    private long max = 10;

    /** 已生成流水號(種子) */
    private long seed = min;

    /** 預生成數量 */
    private int prepare = 4;

    /** 數據庫存儲的當前最大序列號 **/
    long maxSerialInt = 0;

    /** 當前序列號是否為個位數自增的模式 **/
    private String isAutoIncrement = "0";

    /** 預生成流水號 */
    HashMap<String, List<String>> prepareSerialNumberMap = new HashMap<>();



    /**
     * 查詢單條序列號配置信息
     * @param
     * @return
     */
    @Override
    public SystemSerialNumberEntity find(SystemSerialNumberEntity entity) {
        return null;
    }

    /**
     * 根據模塊code生成預數量的序列號存放到Map中
     * @param moduleCode 模塊code
     * @return
     */
    @Transactional
    public List<String> generatePrepareSerialNumbers(String moduleCode){
        //臨時List變量
        List<String> resultList = new ArrayList<String>(prepare);
        lock.lock();
        // 查詢數據庫最大maxSerialInt
        SystemSerialNumberEntity oneByCode = serialNumDao.findOneByCode(moduleCode);
        if(oneByCode == null){
            throw new RuntimeException("不存在模塊code");
        }
        this.maxSerialInt = Long.valueOf(oneByCode.getMaxSerial());
        this.prepare = Integer.valueOf(oneByCode.getPreMaxNum());
        try {
            for (int i = 0; i < prepare; i++) {
                maxSerialInt += 1;
                if(maxSerialInt > min && maxSerialInt < max){
                    seed = maxSerialInt;
                }else {
                    // 如果動態數字長度大於模板中的長度 例:模板CF000  maxSerialInt 1000
                    seed = maxSerialInt = 0;
                }
                // 動態數字生成拼接
                String formatSerialNum = format.format(seed);
                // 動態日期的生成拼接
                if(StringUtils.isNotBlank(pattern)){
                    String date = DateUtils.getDate(pattern);
                    formatSerialNum = date + formatSerialNum;
                }
                if(StringUtils.isNotBlank(oneByCode.getConfigTemplet())){
                    formatSerialNum = oneByCode.getConfigTemplet() + formatSerialNum;
                }
                resultList.add(formatSerialNum);
            }
            //更新數據
            oneByCode.setMaxSerial(maxSerialInt + "");
            serialNumDao.update(oneByCode);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return resultList;
    }

    /**
     * 根據模塊code生成序列號
     * @param moduleCode  模塊code
     * @return  序列號
     */
    @Override
    @Transactional
    public String generateSerialNumberByModelCode(String moduleCode) {
        //預序列號加鎖
        prepareLock.lock();
        try{
            //判斷內存中是否還有序列號
            if(null != prepareSerialNumberMap.get(moduleCode) && prepareSerialNumberMap.get(moduleCode).size() > 0){
                //若有,返回第一個,並刪除
                return prepareSerialNumberMap.get(moduleCode).remove(0);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //預序列號解鎖
            prepareLock.unlock();
        }
        List<String> resultList = generatePrepareSerialNumbers(moduleCode);
        prepareLock.lock();
        try {
            prepareSerialNumberMap.put(moduleCode, resultList);
            return prepareSerialNumberMap.get(moduleCode).remove(0);
        } finally {
            prepareLock.unlock();
        }
    }

}

 

  


免責聲明!

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



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