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的更多相关文章

  1. JDE910笔记1--基础介绍及配置

    1.一般JDE部署后环境: DV:开发环境 PY:测试环境 PD:正式环境 根据端口号区分不同环境,可配置.同时,JDE默认使用分发服务器,不同环境连接为不同的数据库. 2.命名规范: 自定义项目.函 ...

  2. JDE910笔记1--基础介绍及配置[转]

    1.一般JDE部署后环境: DV:开发环境 PY:测试环境 PD:正式环境 根据端口号区分不同环境,可配置.同时,JDE默认使用分发服务器,不同环境连接为不同的数据库. 2.命名规范: 自定义项目.函 ...

  3. oracle 创建自定义的流水号

    ; --你确定流水号只要3位? 使用它的下一个值用: seq_abc_taskid.nextval查询当前值用:seq_abc_taskid.currval比如你现在要插入一行到abc,你可以 ,se ...

  4. Mysql - 存储过程/自定义函数

    在数据库操作中, 尤其是碰到一些复杂一些的系统, 不可避免的, 会用到函数/自定义函数, 或者存储过程. 实际项目中, 自定义函数和存储过程是越少越好, 因为这个东西多了, 也是一个非常难以维护的地方 ...

  5. WPF自定义RoutedEvent事件示例代码

    ************************* 引用网友,便于查找所用..... 创建自定义路由事件和应用分为6个步骤: (1)自定义路由事件参数对象 (2)声明并注册路由事件 (3)为路由事件添 ...

  6. 前端基于JQgrid实现自定义列头展示

    先上效果图   因为公司项目的需要,并且公司只有我这一个能写js的前端,这个自定义展示jqgrid列选项的需求依然是交由我写,辣么就分享一下我的工作成果. //初始化函数 multiSelectCol ...

  7. 自定义Base16加密

                                                                                              自定义Base16加 ...

  8. BarTender怎样同时打印自动日期和流水号?

    大多数条形码中都会含有日期和数量信息,而且大部分都是两者兼具.有些使用BarTender软件的小伙伴,不知道怎么同时打印自动日期和流水号,即条形码中兼有自动日期和序列号,且它们都能根据打印的变化而变化 ...

  9. C# 流水号生成器开发

    前言 本文将使用一个Nuget公开的组件技术来实现一个流水号生成器,提供了一些简单的API,来方便的实现一个通用的流水号. 在visual studio 中的NuGet管理器中可以下载安装,也可以直接 ...

随机推荐

  1. OpenCV学习(7) 分水岭算法(1)

            分水岭算法主要用于图像分段,通常是把一副彩色图像灰度化,然后再求梯度图,最后在梯度图的基础上进行分水岭算法,求得分段图像的边缘线.         下面左边的灰度图,可以描述为右边的地 ...

  2. Linux 查看当前时间和修改系统时间

    一.查看和修改Linux的时区 1. 查看当前时区 命令: date -R 2. 修改设置Linux服务器时区 方法 A 命令 : tzselect 方法 B 仅限于RedHat Linux 和 Ce ...

  3. Python 爬虫 之 阅读呼叫转移(三)

    尽管上一篇博客中我们能够连续地阅读章节了,可是.难道每一次看小说都执行一下我们的 Python 程序?连记录看到哪里都不行,每次都是又一次来过?当然不能这样,改! 如今这么多小说阅读器,我们仅仅须要把 ...

  4. Cocos2d-X中的动作特效

    Cocos2d-X中提供了很丰富的动作特效 比如:网格动画 扭曲特效 3D瓷砖波动特效 程序代码: #include "ActionEffect.h" #include " ...

  5. Thinkphp学习笔记7-输入变量

    在Web开发过程中,我们经常需要获取系统变量或者用户提交的数据,这些变量数据错综复杂,而且一不小心就容易引起安全隐患,但是如果利用好ThinkPHP提供的变量获取功能,就可以轻松的获取和驾驭变量了. ...

  6. Python网络爬虫 - 2. Beautiful Soup小试牛刀

    目标: 我们解析百度首页的logo bs_baidu_logo.py from urllib.request import urlopen from bs4 import BeautifulSoup ...

  7. Javascript的解析器

    Carakan C/C++ http://my.opera.com/core/blog/2009/02... SquirrelFish C++ http://trac.webkit.org/wiki/ ...

  8. Linux crond实例

    linux系统的定时任务: 1:linux系统自身定期执行的任务工作:系统周期性执行的任务工作,如轮询系统日志,备份系统数据,清理系统缓存等. [root@10-4-5-9 ~]# ll /var/l ...

  9. 使用hasOwnProperty监测对象是否含有某个属性

    1.示例代码 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UT ...

  10. org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'statisticalMapper' defined in file

    ::, [localhost-startStop-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFact ...