搜索
首页Javajava教程Java之流水号生成器

Java之流水号生成器

Jan 17, 2017 pm 03:18 PM
java生成器

提出问题

如何使用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实体设计:

[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<String,List<String>> 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<String> generatePrepareSerialNumbers(String moduleCode){
        //临时List变量
        List<String> resultList = new ArrayList<String>(prepare);
        lock.lock();
        try{
            for(int i=0;i<prepare;i++){
                maxSerialInt  = maxSerialInt + 1;
                if(maxSerialInt > 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,&#39;0&#39;) + 1;//根据模板判断当前序列号数字的最大值
        if(isAutoIncrement.equals("1")){
            pattern = pattern.replace("0","#");
        }
        format = new DecimalFormat(pattern);
        //生成预序列号,存到缓存中
        List<String> 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)!


声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JVM如何在不同平台上管理垃圾收集?JVM如何在不同平台上管理垃圾收集?Apr 28, 2025 am 12:23 AM

JVMmanagesgarbagecollectionacrossplatformseffectivelybyusingagenerationalapproachandadaptingtoOSandhardwaredifferences.ItemploysvariouscollectorslikeSerial,Parallel,CMS,andG1,eachsuitedfordifferentscenarios.Performancecanbetunedwithflagslike-XX:NewRa

为什么Java代码可以在不同的操作系统上运行,而无需修改?为什么Java代码可以在不同的操作系统上运行,而无需修改?Apr 28, 2025 am 12:14 AM

Java代码可以在不同操作系统上无需修改即可运行,这是因为Java的“一次编写,到处运行”哲学,由Java虚拟机(JVM)实现。JVM作为编译后的Java字节码与操作系统之间的中介,将字节码翻译成特定机器指令,确保程序在任何安装了JVM的平台上都能独立运行。

描述编译和执行Java程序的过程,突出平台独立性。描述编译和执行Java程序的过程,突出平台独立性。Apr 28, 2025 am 12:08 AM

Java程序的编译和执行通过字节码和JVM实现平台独立性。1)编写Java源码并编译成字节码。2)使用JVM在任何平台上执行字节码,确保代码的跨平台运行。

基础硬件架构如何影响Java的性能?基础硬件架构如何影响Java的性能?Apr 28, 2025 am 12:05 AM

Java性能与硬件架构密切相关,理解这种关系可以显着提升编程能力。 1)JVM通过JIT编译将Java字节码转换为机器指令,受CPU架构影响。 2)内存管理和垃圾回收受RAM和内存总线速度影响。 3)缓存和分支预测优化Java代码执行。 4)多线程和并行处理在多核系统上提升性能。

解释为什么本地库可以破坏Java的平台独立性。解释为什么本地库可以破坏Java的平台独立性。Apr 28, 2025 am 12:02 AM

使用原生库会破坏Java的平台独立性,因为这些库需要为每个操作系统单独编译。1)原生库通过JNI与Java交互,提供Java无法直接实现的功能。2)使用原生库增加了项目复杂性,需要为不同平台管理库文件。3)虽然原生库能提高性能,但应谨慎使用并进行跨平台测试。

JVM如何处理操作系统API的差异?JVM如何处理操作系统API的差异?Apr 27, 2025 am 12:18 AM

JVM通过JavaNativeInterface(JNI)和Java标准库处理操作系统API差异:1.JNI允许Java代码调用本地代码,直接与操作系统API交互。2.Java标准库提供统一API,内部映射到不同操作系统API,确保代码跨平台运行。

Java 9影响平台独立性中引入的模块化如何?Java 9影响平台独立性中引入的模块化如何?Apr 27, 2025 am 12:15 AM

modularitydoesnotdirectlyaffectJava'splatformindependence.Java'splatformindependenceismaintainedbytheJVM,butmodularityinfluencesapplicationstructureandmanagement,indirectlyimpactingplatformindependence.1)Deploymentanddistributionbecomemoreefficientwi

什么是字节码,它与Java的平台独立性有何关系?什么是字节码,它与Java的平台独立性有何关系?Apr 27, 2025 am 12:06 AM

BytecodeinJavaistheintermediaterepresentationthatenablesplatformindependence.1)Javacodeiscompiledintobytecodestoredin.classfiles.2)TheJVMinterpretsorcompilesthisbytecodeintomachinecodeatruntime,allowingthesamebytecodetorunonanydevicewithaJVM,thusfulf

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。