自定义流水号的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管理器中可以下载安装,也可以直接 ...
随机推荐
- Qt Creator怎样更改默认构建目录
用过VS的朋友都知道,用VS编译工程时会将生成的可执行文件放在当前工程目录下,使每个工程独立地成为一个整体,管理起来颇为方便:而Qt Creator则不同,编译程序时会创建一个与当前工程目录同级的构建 ...
- Ubuntu Server 13.10 安装配置图解教程
一.Ubuntu Server 13.10系统安装 Ubuntu分为桌面版(desktop)和服务器版(Server),下面为大家介绍服务器版本Ubuntu Server 13.10的详细安装过程. ...
- [React] Use the useReducer Hook and Dispatch Actions to Update State (useReducer, useMemo, useEffect)
As an alternate to useState, you could also use the useReducer hook that provides state and a dispat ...
- [Firebase] 3. Firebase Simple Login Form
Using $firebaseSimpleLogin service. Here we use three methods for login, logout, register and getCur ...
- UNIX网络编程读书笔记:字节操纵函数
#include <strings.h> void bzero(void *dest, size_t nbytes); void bcopy(const void *src, void * ...
- UNIX网络编程读书笔记:图解TCP端口号和并发服务器
图1 TCP服务器在端口21上执行被动打开 图2 客户对服务器的 ...
- 【转】MVC4验证用户登录特性实现方法
在开发过程中,需要用户登陆才能访问指定的页面这种功能,微软已经提供了这个特性. // 摘要: // 表示一个特性,该特性用于限制调用方对操作方法的访问. [AttributeUsage(Attribu ...
- Java静态变量的初始化(static块的本质)
Java静态变量的初始化(static块的本质) 标签: javaclassstring编译器jdk工作 2010-02-06 07:23 33336人阅读 评论(16) 收藏 举报 分类: Jav ...
- 〖C语言〗C语言一个函数传递无限制多参数(不确定参数函数)的方法
/* * ===================================================================================== * * Filen ...
- Cookie 获取访问时间
服务器将客户端需要缓存的数据,发送到客户端,客户端保存在本地的这些缓存数据就是Cookie.区别于Session. 获取用户访问时间代码: response.setCharacterEncodin ...