zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    
    }

      

  • 相关阅读:
    Servlet细节
    https协议
    常用css缩写
    Servlet
    计算机编码总结
    java 中 finally 语句块的 深度解析 总结
    使用DIV之后 table何去何从
    http协议
    web开发基础
    js闭包之我见
  • 原文地址:https://www.cnblogs.com/chengyangyang/p/10824404.html
Copyright © 2011-2022 走看看