0

0

Java之流水号生成器

黄舟

黄舟

发布时间:2017-01-17 15:18:34

|

2742人浏览过

|

来源于php中文网

原创

提出问题

如何使用java生成流水号,同时支持可配置和高并发???

解决问题

假设你们项目已经整合缓存技术 

假如你有一定的Java基础 

假如……

下面的代码实现的是一个支持高并发,可配置,效率高的流水号生成器,可同时为一个项目的多个模块使用,流水号支持缓存,即每次会预先生成一定数量的流水号存放在缓存中,需要的时候,优先到缓存中去,缓存中的序列号使用完之后,重新生成一定数量的流水号放到缓存中,如此循环,提高效率…… 

同时,该流水号生成器是线程安全的,使用线程锁进行保护,已经真正的投入到项目中使用……

数据库表设计

[code]CREATE TABLE sys_serial_number2 (
    "id" varchar(32) COLLATE "default" NOT NULL,
    "module_name" varchar(50) COLLATE "default",
    "module_code" varchar(50) COLLATE "default",
    "config_templet" varchar(50) COLLATE "default",
    "max_serial" varchar(32) COLLATE "default",
    "pre_max_num" varchar(32) COLLATE "default",
    "is_auto_increment" char(1) COLLATE "default"
)

说明:

[code]module_name:模块名称
module_code:模块编码
config_templet:当前模块 使用的序列号模板
max_serial:存放当前序列号的值
pre_max_num:预生成序列号存放到缓存的个数
is_auto_increment:是否自动增长模式,0:否  1:是

注意:目前序列号模板只支持字母,动态数字(0000 代表1-9999),和日期用${DATE}的组合形式 

is_auto_increment配置为1 ,这时配置模板为CX000000生成的序列号为:CX1 ,CX2,CX3….. 

配置为0,这时配置模板为CX0000000生成的序列号为:CX00000001,CX00000002,CX00000003

数据库配置说明:如需要项目模块的项目编号,则需要在数据库表sys_serial_number中配置一条记录:

[code]|  id   |  module_name |  module_code |  config_templet | max_serial  | pre_max_num |  is_auto_increment
|-------|--------------|--------------|-----------------|-------------|-------------|--------------------/
|  xxxx |  项目         |  PJ         |CX00000000${DATE}|  2650       |  100        |    1

CX00000000${DATE}生成的序列号类似于:CX0000000120160522 ,CX0000000220160522,CX0000000320160522 ……

序列号model实体设计:

立即学习Java免费学习笔记(深入)”;

weiit-saas开源电商SaaS系统
weiit-saas开源电商SaaS系统

weiit-saas是一款Java开源项目,由weiit团队自研,意在通过技术封装,帮助企业一键生成小程序、公众号,让企业拥有独立品牌的自营商城。weiit-saas是完全开源电商SaaS系统,属于weiit开源的社区版,旧版已不在维护和更新,仅供学习和参考,新版saas从底层架构到前后端UI设计已经全面优化和升级。 主要特点1、项目采用Spring+SpringMVC+Mybatis主流开源框架

下载
[code]package com.evada.de.serialnum.model;

import com.evada.de.common.model.BaseModel;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * 功能描述:序列号表模型
 *
 * @author :Ay 2015/11/23
 */
@Entity
@Table(name="sys_serial_number")
public class SystemSerialNumber extends BaseModel {

    /**
     * 模块名称
     */
    @Column(name = "module_name", columnDefinition = "VARCHAR")
    private String moduleName;

    /**
     * 模块编码
     */
    @Column(name = "module_code", columnDefinition = "VARCHAR")
    private String moduleCode;

    /**
     * 流水号配置模板
     */
    @Column(name = "config_templet", columnDefinition = "VARCHAR")
    private String configTemplet;

    /**
     * 序列号最大值
     */
    @Column(name = "max_serial", columnDefinition = "VARCHAR")
    private String maxSerial;

    /**
     * 是否自动增长标示
     */
    @Column(name = "is_auto_increment", columnDefinition = "VARCHAR")
    private String isAutoIncrement;

    public String getIsAutoIncrement() {
        return isAutoIncrement;
    }

    public void setIsAutoIncrement(String isAutoIncrement) {
        this.isAutoIncrement = isAutoIncrement;
    }

    /**
     * 预生成流水号数量
     */
    @Column(name = "pre_max_num", columnDefinition = "VARCHAR")
    private String preMaxNum;

    public String getPreMaxNum() {
        return preMaxNum;
    }

    public void setPreMaxNum(String preMaxNum) {
        this.preMaxNum = preMaxNum;
    }

    public String getModuleName() {
        return moduleName;
    }

    public void setModuleName(String moduleName) {
        this.moduleName = moduleName;
    }

    public String getModuleCode() {
        return moduleCode;
    }

    public void setModuleCode(String moduleCode) {
        this.moduleCode = moduleCode;
    }

    public String getConfigTemplet() {
        return configTemplet;
    }

    public void setConfigTemplet(String configTemplet) {
        this.configTemplet = configTemplet;
    }

    public String getMaxSerial() {
        return maxSerial;
    }

    public void setMaxSerial(String maxSerial) {
        this.maxSerial = maxSerial;
    }

    public SystemSerialNumber(String id){
        this.id = id;
    }

    public  SystemSerialNumber(String id,String moduleCode){
        this.id = id;
        this.moduleCode = moduleCode;
    }

    public SystemSerialNumber(){}
}

Service接口设计:

[code]package com.evada.de.serialnum.service;

import com.evada.de.serialnum.dto.SystemSerialNumberDTO;

/**
 * 序列号service接口
 * Created by huangwy on 2015/11/24.
 */
public interface ISerialNumService {

    public SystemSerialNumberDTO find(SystemSerialNumberDTO systemSerialNumberDTO);

    public String generateSerialNumberByModelCode(String moduleCode);

    /**
     * 设置最小值
     * @param value 最小值,要求:大于等于零
     * @return      流水号生成器实例
     */
    ISerialNumService setMin(int value);

    /**
     * 设置最大值
     * @param value 最大值,要求:小于等于Long.MAX_VALUE ( 9223372036854775807 )
     * @return      流水号生成器实例
     */
    ISerialNumService setMax(long value);

    /**
     * 设置预生成流水号数量
     * @param count 预生成数量
     * @return      流水号生成器实例
     */
    ISerialNumService setPrepare(int count);
}

Service实现:

[code]package com.evada.de.serialnum.service.impl;

import com.evada.de.common.constants.SerialNumConstants;
import com.evada.de.serialnum.dto.SystemSerialNumberDTO;
import com.evada.de.serialnum.model.SystemSerialNumber;
import com.evada.de.serialnum.repository.SerialNumberRepository;
import com.evada.de.serialnum.repository.mybatis.SerialNumberDAO;
import com.evada.de.serialnum.service.ISerialNumService;
import com.evada.inno.common.util.BeanUtils;
import com.evada.inno.common.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Ay on 2015/11/24.
 */
@Service("serialNumberService")
public class SerialNumberServiceImpl implements ISerialNumService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SerialNumberServiceImpl.class);

    @Autowired
    private SerialNumberDAO serialNumberDAO;

    @Autowired
    private SerialNumberRepository serialNumberRepository;

    /** 格式 */
    private String pattern = "";

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

    /** 流水号格式化器 */
    private DecimalFormat format = null;

    /** 预生成锁 */
    private final ReentrantLock prepareLock = new ReentrantLock();

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

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

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

    /** 预生成数量 */
    private int prepare = 0;

    /** 数据库存储的当前最大序列号 **/
    long maxSerialInt = 0;

    /** 当前序列号是否为个位数自增的模式 **/
    private String isAutoIncrement = "0";

    SystemSerialNumberDTO systemSerialNumberDTO =  new SystemSerialNumberDTO();

    /** 预生成流水号 */
    HashMap> prepareSerialNumberMap = new HashMap<>();

    /**
     * 查询单条序列号配置信息
     * @param systemSerialNumberDTO
     * @return
     */
    @Override
    public SystemSerialNumberDTO find(SystemSerialNumberDTO systemSerialNumberDTO) {
        return serialNumberDAO.find(systemSerialNumberDTO);
    }

    /**
     * 根据模块code生成预数量的序列号存放到Map中
     * @param moduleCode 模块code
     * @return
     */
    @CachePut(value = "serialNumber",key="#moduleCode")
    public List generatePrepareSerialNumbers(String moduleCode){
        //临时List变量
        List resultList = new ArrayList(prepare);
        lock.lock();
        try{
            for(int i=0;i
 min && (maxSerialInt + "").length() < max ){
                    seed = maxSerialInt ;
                }else{
                    //如果动态数字长度大于模板中的长度 例:模板CF000  maxSerialInt 1000
                    seed = maxSerialInt = 0;
                    //更新数据,重置maxSerialInt为0
                    systemSerialNumberDTO.setMaxSerial("0");
                    SystemSerialNumber systemSerialNumber = new SystemSerialNumber();
                    BeanUtils.copyProperties(systemSerialNumber,systemSerialNumberDTO);
                    serialNumberRepository.save(systemSerialNumber);
                }
                 //动态数字生成
                 String formatSerialNum = format.format(seed);

                //动态日期的生成
                if(pattern.contains(SerialNumConstants.DATE_SYMBOL)){
                    String currentDate = DateUtils.format(new Date(),"yyyyMMdd");
                    formatSerialNum = formatSerialNum.replace(SerialNumConstants.DATE_SYMBOL,currentDate);
                }

                resultList.add(formatSerialNum);
            }
            //更新数据
            systemSerialNumberDTO.setMaxSerial(maxSerialInt + "");
            SystemSerialNumber systemSerialNumber = new SystemSerialNumber();
            BeanUtils.copyProperties(systemSerialNumber,systemSerialNumberDTO);
            serialNumberRepository.save(systemSerialNumber);
        }finally{
            lock.unlock();
        }
        return resultList;
    }

    /**
     * 根据模块code生成序列号
     * @param moduleCode  模块code
     * @return  序列号
     */
    public String generateSerialNumberByModelCode(String moduleCode){

        //预序列号加锁
        prepareLock.lock();
        try{
            //判断内存中是否还有序列号
            if(null != prepareSerialNumberMap.get(moduleCode) && prepareSerialNumberMap.get(moduleCode).size() > 0){
                //若有,返回第一个,并删除
                return prepareSerialNumberMap.get(moduleCode).remove(0);
            }
        }finally {
            //预序列号解锁
            prepareLock.unlock();
        }
        systemSerialNumberDTO = new SystemSerialNumberDTO();
        systemSerialNumberDTO.setModuleCode(moduleCode);
        systemSerialNumberDTO = serialNumberDAO.find(systemSerialNumberDTO);
        prepare = Integer.parseInt(systemSerialNumberDTO.getPreMaxNum().trim());//预生成流水号数量
        pattern = systemSerialNumberDTO.getConfigTemplet().trim();//配置模板
        String maxSerial = systemSerialNumberDTO.getMaxSerial().trim(); //存储当前最大值
        isAutoIncrement = systemSerialNumberDTO.getIsAutoIncrement().trim();
        maxSerialInt = Long.parseLong(maxSerial.trim());//数据库存储的最大序列号
        max = this.counter(pattern,'0') + 1;//根据模板判断当前序列号数字的最大值
        if(isAutoIncrement.equals("1")){
            pattern = pattern.replace("0","#");
        }
        format = new DecimalFormat(pattern);
        //生成预序列号,存到缓存中
        List resultList = generatePrepareSerialNumbers(moduleCode);
        prepareLock.lock();
        try {
            prepareSerialNumberMap.put(moduleCode, resultList);
            return prepareSerialNumberMap.get(moduleCode).remove(0);
        } finally {
            prepareLock.unlock();
        }
    }

    /**
     * 设置最小值
     *
     * @param value 最小值,要求:大于等于零
     * @return 流水号生成器实例
     */
    public ISerialNumService setMin(int value) {
        lock.lock();
        try {
            this.min = value;
        }finally {
            lock.unlock();
        }
        return this;
    }

    /**
     * 最大值
     *
     * @param value 最大值,要求:小于等于Long.MAX_VALUE ( 9223372036854775807 )
     * @return 流水号生成器实例
     */
    public ISerialNumService setMax(long value) {
        lock.lock();
        try {
            this.max = value;
        }finally {
            lock.unlock();
        }
        return this;
    }

    /**
     * 设置预生成流水号数量
     * @param count 预生成数量
     * @return      流水号生成器实例
     */
    public ISerialNumService setPrepare(int count) {
        lock.lock();
        try {
            this.prepare = count;
        }finally {
            lock.unlock();
        }
        return this;
    }

    /**
     * 统计某一个字符出现的次数
     * @param str 查找的字符
     * @param c
     * @return
     */
    private int counter(String str,char c){
        int count=0;
        for(int i = 0;i < str.length();i++){
            if(str.charAt(i)==c){
                count++;
            }
        }
        return count;
    }

}

以上就是Java之流水号生成器的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
云朵浏览器入口合集
云朵浏览器入口合集

本专题整合了云朵浏览器入口合集,阅读专题下面的文章了解更多详细地址。

0

2026.01.20

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

20

2026.01.20

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

62

2026.01.19

java用途介绍
java用途介绍

本专题整合了java用途功能相关介绍,阅读专题下面的文章了解更多详细内容。

87

2026.01.19

java输出数组相关教程
java输出数组相关教程

本专题整合了java输出数组相关教程,阅读专题下面的文章了解更多详细内容。

39

2026.01.19

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

10

2026.01.19

xml格式相关教程
xml格式相关教程

本专题整合了xml格式相关教程汇总,阅读专题下面的文章了解更多详细内容。

13

2026.01.19

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

19

2026.01.19

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

160

2026.01.18

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.7万人学习

C# 教程
C# 教程

共94课时 | 7.2万人学习

Java 教程
Java 教程

共578课时 | 48.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号