分布式id-数据库段号方式


public class SequenceUtil {
    
    private static Logger logger = LoggerFactory.getLogger(SequenceUtil.class);

    /** 存当前不同类型ID值 **/
    private static HashMap<String, SequenceInfo> currSeqMap = new HashMap<String, SequenceInfo>();
    
    /**ID_COMMON*/
    private static String ID_COMMON ="ID_COMMON";
    
    /***
     * <b>说明:</b> 获取表唯一ID,为19位字符,(表类型3位+日期6位+数据库sequence 6位+内存自增记数4位)
     * 
     * @param
     * @return
     * @author costin_law
     * @since 2014年5月26日
     */
    public static String getId(UniqueIdCode idCode) {
        StringBuffer strBuff = new StringBuffer(19); 
        if(StringUtils.isBlank(idCode.getCode()) || (2 != idCode.getCode().length() && 3 != idCode.getCode().length())){
            throw new IllegalArgumentException("uniqueIdCode format error");
        }
        if(2 == idCode.getCode().length()){
            strBuff.append("C").append(idCode.getCode()); // +3            
        }else{
            strBuff.append(idCode.getCode()); // +3          
        }
        strBuff.append(DateUtil.getCurDate(DateUtil.DATE_FROMAT_YYMMDD)); // +6
        
        String sequenceName = idCode.getSequenceName();
        if(StringUtils.isBlank(sequenceName)){
            sequenceName = ID_COMMON;
        }
        long value = getNextValue(sequenceName,4);
        strBuff.append(StringFillUtil.LeftFill(String.valueOf(value), '0', 10));
        return strBuff.toString();
    }

    /***
     * 根据指定的sequenceCode 获取序列值
     * 
     * @param sequenceCode
     * @param size
     *            缓存到内存中的位数
     * @return long
     * @author costin_law
     *
     */
    protected static long getNextValue(String idType,int size) {
        long intPow = (long) Math.pow(10, size);

        SequenceInfo sequenceInfo = currSeqMap.get(idType);
        if (sequenceInfo == null ) {
            synchronized(currSeqMap){
                sequenceInfo = currSeqMap.get(idType);
                if( sequenceInfo == null){
                    sequenceInfo = new SequenceInfo(); 
                    currSeqMap.put(idType,sequenceInfo);
                }
            }        
        }
        
        long seqValue = sequenceInfo.seqNo.incrementAndGet();
        long oldDbSeq = sequenceInfo.dbSeq;
        //如果判断当前号段是否用完,用完则从数据库取新号段
        while( seqValue >= intPow || oldDbSeq <= 0 ){
            synchronized (sequenceInfo) {
                if( oldDbSeq  == sequenceInfo.dbSeq ){

                    sequenceInfo.dbSeq = getDbSeqValue(idType);
                    seqValue = 1;
                    sequenceInfo.seqNo.set(seqValue);     
                }else{
                    seqValue = sequenceInfo.seqNo.incrementAndGet();                    
                }
                
                oldDbSeq = sequenceInfo.dbSeq;
            }      
        }

        return (oldDbSeq * intPow) + seqValue;
    }

    /**
     * <b>说明:</b> 根据指定的序列值获取值
     * 
     * @param
     * @return
     * @throws ServiceException
     * @author costin_law
     *
     */
    private static long getDbSeqValue(String idType) {
            /*DataSource dataSource = (DataSource) SpringContextHolder.getBean("dataSource");
            OracleSequenceMaxValueIncrementer sequence = new OracleSequenceMaxValueIncrementer();
            sequence.setDataSource(dataSource);
            sequence.setIncrementerName(sequenceCode.getCode());*/
        
            SequenceDao sequenceDao = SpringContextHolder.getBean("sequenceDao");
            try {
                return sequenceDao.getSequenceValue(idType);
            } catch(Exception e1) {
                for (int i=0; i<3; i++) {
                    try {
                        Random random=new Random();
                        long randomMs = random.nextInt(1001)+1000;
                        Thread.sleep(randomMs);
                        return sequenceDao.getSequenceValue(idType);
                    } catch(Exception e2) {
                        logger.error("第" + i + "次获取失败");
                    }
                }
                
                throw e1;
            }
    }

   
    
    static class SequenceInfo{
        long dbSeq = -1;
        AtomicLong seqNo = new AtomicLong(-1);   
    }
}
 

@Service("sequenceDao")
public class SequenceDao {

    private static Logger logger = LoggerFactory.getLogger(SequenceDao.class);

    private void updateSequence(Connection connection, String sequenceName, Map<String,Long> resultMap) throws SQLException {
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement("UPDATE SMY.SEQUENCE_INFO set SEQUENCE_VALUE=?,UPDATE_TIME=NOW() WHERE SEQUENCE_NAME=? AND SEQUENCE_VALUE=?");
            
            
            long seqCurrValue = resultMap.get("seqCurrValue");
            long maxValue = resultMap.get("maxValue");
            long seqLen = resultMap.get("seqLen");
            long increment = resultMap.get("increment");
            long startValue = resultMap.get("startValue");
            
            long seqNextValue = seqCurrValue + increment;
            if (seqNextValue >= maxValue || seqNextValue > (Math.pow(10, seqLen) - 1)) {
                seqNextValue = startValue;
            } 
            
            ps.setLong(1, seqNextValue);
            ps.setString(2, sequenceName);
            ps.setLong(3, seqCurrValue);
            int cnt = ps.executeUpdate();

            logger.debug("更新流水号[{}],参数{}", sequenceName, seqNextValue);
            if (cnt != 1 || ps.getUpdateCount() != 1) {
                logger.error("更新流水号[{}]信息失败,返回更新记录数{}", sequenceName, cnt);
                throw new RuntimeException("update sequence error[" + sequenceName + "]");
            }
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }

    private void insertSequence(Connection connection, String sequenceName) throws SQLException {
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement("INSERT INTO SMY.SEQUENCE_INFO (SEQUENCE_NAME,SEQUENCE_VALUE,MAX_VALUE,SEQUENCE_LEN,INCREMENT,START_VALUE) VALUES(?,?,?,?,?,?)");

            ps.setString(1, sequenceName);
            ps.setLong(2, 10);
            ps.setLong(3, 999999);
            ps.setInt(4, 6);
            ps.setInt(5, 1);
            ps.setInt(6, 10);
            ps.execute(); 

            logger.debug("新增流水号[{}],成功", sequenceName);
            
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }

    private Map<String,Long> querySequence(Connection connection, String sequenceName) throws SQLException {
        PreparedStatement ps = null;
        ResultSet rs = null;
        Map<String,Long> resultMap = new HashMap<String,Long>();
        try {
            logger.debug("开始从数据库取分段流水[" + sequenceName + "]");
            ps = connection.prepareStatement("SELECT SEQUENCE_VALUE, MAX_VALUE, SEQUENCE_LEN, INCREMENT, START_VALUE " + " from SMY.SEQUENCE_INFO where SEQUENCE_NAME=? ");
            ps.setString(1, sequenceName);
            rs = ps.executeQuery();
            if (rs.next()) {
                long seqCurrValue = rs.getLong(1);
                long maxValue = rs.getLong(2);
                long seqLen = rs.getLong(3);
                long increment = rs.getLong(4);
                long startValue = rs.getLong(5);

                resultMap.put("seqCurrValue",seqCurrValue);
                resultMap.put("maxValue", maxValue);
                resultMap.put("seqLen", seqLen);
                resultMap.put("startValue", startValue);
                resultMap.put("increment", increment);
                
                logger.debug("取分段流水[" + sequenceName + "]完成");
                return resultMap;
            } else {
                resultMap.put("seqCurrValue",-1L);
                return resultMap;
            }

        } finally {
            if (rs != null) {
                rs.close();// 释放数据库锁
            }
            if (ps != null) {
                ps.close();
            }
        }
    }
    @Transactional(propagation=Propagation.REQUIRES_NEW)    
    public long getSequenceValue(String sequenceName) {
        SqlSessionFactory sqlSessionFactory = SpringContextHolder.getBean("sqlSessionFactory");
        SqlSession sqlSession = sqlSessionFactory.openSession(false);
        Connection conn = sqlSession.getConnection();

        try {
            // openSession指定autoCommit=false不起作用, 只对通过session的方法执行的有效,只能自己再设置一次
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            logger.error("关闭连接自动事务提交异常!");
        }

        try {
            Map<String, Long> resultMap = querySequence(conn, sequenceName);
            long seqCurrValue = resultMap.get("seqCurrValue");
            //没找到,就新增sequence
            if(seqCurrValue == -1){
                insertSequence(conn, sequenceName);
                resultMap = querySequence(conn, sequenceName);
                seqCurrValue = resultMap.get("seqCurrValue");
            }
                            
            updateSequence(conn, sequenceName, resultMap);

            conn.commit();
            return seqCurrValue;
        } catch (SQLException sqlE) {
            logger.warn("取分段流水出现异常,流水名称:{}.", sequenceName, sqlE);
            throw new RuntimeException("obtain sequence error[" + sequenceName + "]");
        } finally {
            sqlSession.close(); 
        }
    }

}
 

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值