所有示例均在gihub(ssh_base)中====>https://github.com/chengyangyang

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();
        }
    }

}

 

  

posted @ 2019-05-07 11:34  ☞书香门第☜  阅读(2120)  评论(0编辑  收藏  举报
http://count.knowsky.com/count1/count.asp?id=434520&sx=1&ys=64"