开心一笑

提出问题

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

解决问题

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

假如你有一定的Java基础

假如……

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

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

数据库表设计

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"

)

说明:

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中配置一条记录:

| 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实体设计:

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接口设计:

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实现:

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

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,‘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 流水账号生成器_Java之流水号生成器(示例代码)相关推荐

  1. java继承类大全_Java 面向对象继承部分(示例代码)

    被继承的类称为父类(超类),继承父类的类称为子类(派生类) 通过继承可以实现代码重用 子类拥有父类非 private 的属性.方法. 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展. 子类可以 ...

  2. java访问excel表格_Java读取excel表格(示例代码)

    Java读取excel表格 一般都是用poi技术去读取excel表格的,但是这个技术又是什么呢 什么是Apache POI? Apache POI是一种流行的API,它允许程序员使用Java程序创建, ...

  3. python代码大全和用法用量_Python生成器的使用方法和示例代码

    本文是<Effect Python 编写高质量Python代码的59个有效方法>的学习笔记.主要记录生成器的使用方法和示例代码. 返回队列的函数 如果函数要产生一系列结果,那么最简单的做法 ...

  4. Java Singleton类中的线程安全性的示例代码

    Java Singleton类中的线程安全性的示例代码 Singleton是最广泛使用的创建设计模式之一,用于限制应用程序创建对象.在实际应用程序中,数据库连接或企业信息系统(EIS)等资源是有限的, ...

  5. 纯java pdf转换成html,JAVA实现PDF转HTML文档的示例代码

    本文是基于PDF文档转PNG图片,然后进行图片拼接,拼接后的图片转为base64字符串,然后拼接html文档写入html文件实现PDF文档转HTML文档. 引入Maven依赖 org.apache.p ...

  6. java io读取文件_java io读取文件操作代码实例

    这篇文章主要介绍了java io读取文件操作代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 主要分为字节读取和字符读取,字节读取可以一个一个 ...

  7. java实现图像对比度增强_java图片对比度调整示例代码

    java图片对比度调整示例代码 发布于 2020-12-31| 复制链接 摘记: 前言本文主要给大家介绍了关于java图片对比度调整的方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍 ...

  8. java 读excel 流_Java 读取excel 文件流代码实例

    这篇文章主要介绍了Java 读取excel 文件流代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下public static voi ...

  9. java通过单号判断快递公司的示例代码

    通过单号判断快递公司的示例代码有很多种,以下是快递100Java智能单号判断功能接入. 不过首先要拿到快递100的测试账号和密钥,获取方式只需要去官网注册后,登录后台进入用户信息模块就能看到了. ht ...

  10. java 流水账号生成器_Java流水生成工具

    package com.serialnumber; import java.text.SimpleDateFormat; import java.util.Date; import org.apach ...

最新文章

  1. 命令行 上下文环境 与 相对路径
  2. linux screen 配置
  3. Sympy常见多个变量【一行代码创建】
  4. android intent和intent action大全
  5. ecshop根目录调用_ECSHOP各文件夹功能说明
  6. FinTech专题:支付平台建设资金底线防火墙的杀手级设计方案
  7. go string 转 uint64_如何优雅的使用Go接口?
  8. vscode 配置import @ 路径提示及代码智提
  9. fastreport文本字数太多换行_Python教程第10篇:聊聊print换行输出和重复多次打印...
  10. 18.TCP/IP 详解卷1 --- TCP 连接的建立与终止
  11. sql server managerment 给表加说明
  12. 你好Haskell (1) 环境搭建和简单玩玩
  13. 【软件测试】大厂测试开发你真的了解吗?测试开发养成记......
  14. ps去掉图片上的文字的6种方法
  15. Python学习笔记——eofs.standard的使用
  16. springboot+uniapp实现简单注册登录
  17. linux查询awk命令用法
  18. 自动驾驶之点云与图像融合综述
  19. python 把matplotlib绘制的图片显示到html中
  20. Chinaren校友录

热门文章

  1. html中icon小图标大全,iconfont字体图标和各种CSS小图标
  2. winform自定义panel控件
  3. Qt中添加鼠标右键菜单
  4. 无线网络密码破解方法
  5. 变色龙引导安装mac
  6. struts2之拦截器详解
  7. 【转载】福昕PDF电子文档处理套件 企业版 注册码 注册方法
  8. 索尼z5原生android6.0,索尼Z5怎么刷安卓6.0?索尼Z5刷安卓6.0固件包教程
  9. python数据透视表对各列统计_python pandas数据分析基础入门2——(数据格式转换、排序、统计、数据透视表)...
  10. SWF怎么转FLV格式?