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; /** * * 自动编码工具类 调用 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 executeCount = new ThreadLocal (){ @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 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); } }