自定义流水号的autocode
package cn.com.do1.component.yopin.util;
import cn.com.do1.common.dac.QuickDAC;
import cn.com.do1.common.exception.BaseException;
import cn.com.do1.common.util.AssertUtil;
import cn.com.do1.dqdp.core.DqdpAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* 自动编码工具类 <br/>调用 AutoCodeUtil.getAutoCode("传入编码前缀字符串")
* @author ao.ouyang
* 2015-4-23 10:00:17
*/
public final class AutoCodeUtil {
private final static Logger log = LoggerFactory.getLogger(AutoCodeUtil.class);
private final static ThreadLocal<Integer> executeCount = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
private static DataSource ds;
private static AutoCodeUtil util;
private final static Lock lock = new ReentrantLock(true);
private AutoCodeUtil() {
ds = DqdpAppContext.getSpringContext().getBean(DataSource.class);
}
public static AutoCodeUtil getInstance() {
if (null == util) {
lock.lock();
try {
util = new AutoCodeUtil();
} finally {
lock.unlock();
}
}
return util;
}
/**
* 这个方法不能直接调用,因为没有加锁来控制并发
* @param type
* @return
* @throws BaseException
*/
private long getCurrentVal(String type) throws BaseException {
try {
Connection conn = ds.getConnection();
QuickDAC dac = null;
try {
dac = new QuickDAC(conn);
dac.preparedSql("select BEGINNING_VAL,INCREASE_STEP,CURRENT_VAL from tb_sequence t where t.val_type = UCASE(:type)");
dac.setPreValue("type", type);
Map<String, Long> query = dac.executeQuery();
if (!AssertUtil.isEmpty(query)) {
dac.preparedSql("update tb_sequence set current_val = case when current_val + increase_step > beginning_val then current_val + increase_step else beginning_val end where val_type = UCASE(:type)");
dac.setPreValue("type", type);
dac.executeUpdate();
return Math.max(query.get("CURRENT_VAL") + query.get("INCREASE_STEP"), query.get("BEGINNING_VAL"));
} else {
dac.preparedSql("insert into tb_sequence(val_type,current_val) values(UCASE(:type), :val)");
dac.setPreValue("type", type).setPreValue("val", 1);
dac.executeUpdate();
log.info("创建新的类别流水号:{}", type);
return 1L;
}
} finally {
if (null != dac)
dac.destoryWithoutConnection();
if (null != conn)
conn.close();
}
} catch (SQLException e) {
throw new BaseException(String.format("获取%s系统流水号失败", type), e);
}
}
private long getCurrentValAndLock(String type) throws BaseException {
try {
if (lock.tryLock(30, TimeUnit.MILLISECONDS)) {
try {
executeCount.set(0);
return this.getCurrentVal(type);
} finally {
lock.unlock();
}
} else {
log.warn("在指定的时间内未能获取指定类别的流水号:{}", type);
if (5 <= executeCount.get()) {
log.error("系统连续5次获取指定类别的流水号失败:{}", type);
return -1L;
}
executeCount.set(executeCount.get() + 1);
return getCurrentValAndLock(type);
}
} catch (InterruptedException e) {
throw new BaseException(e);
}
}
/**
* 流水号开头,不包括type这个类别标识,生成的流水号:00000002321
* @param type
* @param length
* @return
* @throws BaseException
*/
private String currentSequence(String type, int length) throws BaseException {
long value = getInstance().getCurrentValAndLock(type);
StringBuilder sb = new StringBuilder("0000000000000000000");
sb.append(value); //sb=00000000000000000001234567
sb.reverse(); //sb=76543210000000000000000000
sb.setLength(length); //sb=7654321000
return sb.reverse().toString(); //sb=0001234567
}
/**
* 按照指定类别名称,获取当前流水号,返回的流水号开头显示类别名称
* @param type 流水类别名称
* @return
* @throws BaseException
*/
public String currentSequence(String type) throws BaseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHH");
return type + sdf.format(new Date()) + this.currentSequence(type, 5);
}
/**
* 按默认类别获取当前的流水号,返回的流水号开头不显示类别名称
* @return
* @throws BaseException
*/
public String currentSequence() throws BaseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHH");
return sdf.format(new Date()) + this.currentSequence("default", 8);
}
}
自定义流水号的autocode的更多相关文章
- JDE910笔记1--基础介绍及配置
1.一般JDE部署后环境: DV:开发环境 PY:测试环境 PD:正式环境 根据端口号区分不同环境,可配置.同时,JDE默认使用分发服务器,不同环境连接为不同的数据库. 2.命名规范: 自定义项目.函 ...
- JDE910笔记1--基础介绍及配置[转]
1.一般JDE部署后环境: DV:开发环境 PY:测试环境 PD:正式环境 根据端口号区分不同环境,可配置.同时,JDE默认使用分发服务器,不同环境连接为不同的数据库. 2.命名规范: 自定义项目.函 ...
- oracle 创建自定义的流水号
; --你确定流水号只要3位? 使用它的下一个值用: seq_abc_taskid.nextval查询当前值用:seq_abc_taskid.currval比如你现在要插入一行到abc,你可以 ,se ...
- Mysql - 存储过程/自定义函数
在数据库操作中, 尤其是碰到一些复杂一些的系统, 不可避免的, 会用到函数/自定义函数, 或者存储过程. 实际项目中, 自定义函数和存储过程是越少越好, 因为这个东西多了, 也是一个非常难以维护的地方 ...
- WPF自定义RoutedEvent事件示例代码
************************* 引用网友,便于查找所用..... 创建自定义路由事件和应用分为6个步骤: (1)自定义路由事件参数对象 (2)声明并注册路由事件 (3)为路由事件添 ...
- 前端基于JQgrid实现自定义列头展示
先上效果图 因为公司项目的需要,并且公司只有我这一个能写js的前端,这个自定义展示jqgrid列选项的需求依然是交由我写,辣么就分享一下我的工作成果. //初始化函数 multiSelectCol ...
- 自定义Base16加密
自定义Base16加 ...
- BarTender怎样同时打印自动日期和流水号?
大多数条形码中都会含有日期和数量信息,而且大部分都是两者兼具.有些使用BarTender软件的小伙伴,不知道怎么同时打印自动日期和流水号,即条形码中兼有自动日期和序列号,且它们都能根据打印的变化而变化 ...
- C# 流水号生成器开发
前言 本文将使用一个Nuget公开的组件技术来实现一个流水号生成器,提供了一些简单的API,来方便的实现一个通用的流水号. 在visual studio 中的NuGet管理器中可以下载安装,也可以直接 ...
随机推荐
- informatica powercenter学习笔记(三)
以前在做DBA时在DB里写过行转列,列转行的CODE.这两天做了一下测试用INFORMATICA来实现行列互换的功能. 列转行的SQL 实现 ENV: RMDB TABLE: SALES STOREN ...
- 使用CadLib实现CAD(dxf、dwg格式)文件的读取和显示 【转】
参考文章:CadLib 3.5 documentationhttps://www.woutware.com/doc/cadlib3.5/Index.aspx 读取:定义DxfModel类型的变量mod ...
- java学习笔记12--异常处理
java学习笔记系列: java学习笔记11--集合总结 java学习笔记10--泛型总结 java学习笔记9--内部类总结 java学习笔记8--接口总结 java学习笔记7--抽象类与抽象方法 j ...
- android4.0 USB Camera实例(三)UVC
前面我写了两篇文章说明了zc301的实现 详细请看 http://blog.csdn.net/hclydao/article/details/21235919 以下顺便把通用的USB也写上 前面的ZC ...
- mysql的数据恢复
转载自:http://ourmysql.com/archives/1293 数据库数据被误删除是经常看到的事情,数据的恢复也就自然成为了DBA很重要的一门基本功夫,比较笨拙的办法是拉出历史的备份到另外 ...
- Eureka 的 Application Service client的注冊以及执行演示样例
Eureka 服务器架起来了(关于架设步骤參考博客<Linux 下 Eureka 服务器的部署>),如今怎样把我们要负载均衡的服务器(也就是从 Application Cl ...
- 使用ionic播放轮询广告的方法
使用ionic中的ion-slide-box实现,下面是完整的代码示例: <!DOCTYPE html> <html ng-app="app"> <h ...
- 修复错误配置/etc/fstab文件导致系统无法正常启动
1.文件介绍 /etc/fstab这个文件描述系统中各种文件系统的信息,应用程序读取这个文件,然后根据其内容进行自动挂载的工作.作为系统配置文件,fstab通常都位于/etc目录下,它包括了所有分 ...
- 你远比想象中强大pdf
读后感: 序 一.强化自我认知 认识你自己 你认为什么东西是最重要的呢? 这个问题的答案就是价值观. 让定期审视人生成为习惯 除去恐惧 树立目标 二.改变思维模式 选择,记住你的选择(做决定) 巅 ...
- JUnit单元测试基础要点
JUnit单元测试基础要点 1.JUnit是一种测试代码的框架,测试的目的是:保证代码没错,而不是保证代码正确. 2.测试类一般不要和目标类放在一起,但编译成的class文件是放在一起的. 3.单元测 ...