java环境下,订单号或者流水号的生成方法(1)

方法一:

(一).订单号、流水号要求:

  1. 单数据库下支持高并发
  2. 唯一的新单号,不保证连续性
  3. 不保存数据库内唯一,保证表内唯一

 (二).设计思路

  1. 如何保证数据唯一?

       先看下单号样例:A04190701000001 。

       A04:组织代码,190701:当前年月日,000001:可变长度流水号。

       通过组织代码+当前年月日+定长流水号,保证单表内唯一。

     2.如何保证单表为唯一?

       数据库中记录的形式。数据库中将存在流水生成记录表,记录如下字段:

       name(PO对象class名_组织代码_当前年月日),value(当前生成次数)。

       生成sql存储过程,获取流水序号。

(三).代码实现

/**
 * 生成序列号的工具。 <br>
 * 可支持单数据库的并发操作。
 */
public class SequenceGenerator {
  private static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
  private static final int DEFAULT_FLOW_NO_LEN = 6;

  /**
   * 生成定长序列号。
   * 
   * @param name
   *          名称
   * @param len
   *          长度
   * @return
   * @throws ServiceException
   */
  public static String nextValue(String name, int len) throws ServiceException {
    Assert.assertArgumentNotNull(name, "name");

    int value = nextValue(name);
    return String.format("%0" + len + "d", value);
  }

  /**
   * 生成序列号。
   * 
   * @param name
   *          序列名称。
   * @return
   * @throws ServiceException
   */
  public static int nextValue(String name) throws ServiceException {
    Assert.assertArgumentNotEmpty(name, "name");

    String sql = "select _nextval(?) v";
    ICommonDao commonDao = ApplicationContextUtil.getBean(ICommonDao.class);
    Map<String, Object> results = commonDao.findOneForJdbc(sql, name);
    if (results.size() <= 0) {
      throw new ServiceException("生成序列号失败");
    }

    Object value = results.get("v");
    if (value == null) {
      throw new ServiceException("生成序列号失败");
    }
    return (Integer) value;
  }

  /**
   * 生成单号。 <br>
   * 默认6位流水号
   * 
   * @param billClass
   *          单据对象类。
   * @return 唯一的新单号,但不保证连续性。
   * @throws ServiceException
   */
  public static String nextBillNumber(Class<?> billClass) throws ServiceException {
    return nextBillNumber(billClass.getSimpleName(), DEFAULT_FLOW_NO_LEN);
  }

  /**
   * 生成单号。 <br>
   * 默认6位流水号
   * 
   * @param billType
   *          单据类型,一般取实体短名称,禁止为null。
   * @return 唯一的新单号,但不保证连续性。
   * @throws ServiceException
   */
  public static String nextBillNumber(String billType) throws ServiceException {
    return nextBillNumber(billType, DEFAULT_FLOW_NO_LEN);
  }

  /**
   * 生成单号。
   * 
   * @param billType
   *          单据类型,一般取实体短名称,禁止为null。
   * @param flowNumLenth
   *          流水号长度。-1表示不固定长度。
   * @return 唯一的新单号,但不保证连续性。
   * @throws ServiceException
   */
  public static String nextBillNumber(String billType, int flowNumLenth) throws ServiceException {
    final String orgCode = "A04";
    return nextBillNumber(billType, orgCode, flowNumLenth);
  }

  /**
   * 生成单号。 <br>
   * 生成规格: 5位组织代码 + 6位日期(yyMMdd) + flowNumLenth位流水号。 其中,流水号每日重复计算。 <br>
   * 示例: 00001 161206 00001
   * 
   * @param billType
   *          单据类型,一般取实体短名称,禁止为null。
   * @param orgCode
   *          当前组织代码,可空。
   * @param flowNumLenth
   *          流水号长度。-1表示不固定长度。
   * @return 唯一的新单号,但不保证连续性。
   * @throws ServiceException
   */
  public static String nextBillNumber(String billType, String orgCode, int flowNumLenth)
      throws ServiceException {
    Assert.assertArgumentNotEmpty(billType, "billType");

    String suffix = StringUtils.trimToEmpty(orgCode);
    if (StringUtils.isNotBlank(suffix)) {
      suffix += "_";
    }
    final String dateStr = sdf.format(new Date());
    suffix += dateStr;

    // 取流水号
    final String key = billType + "_" + suffix;
    final int value = nextValue(key);
    String test = String.format("%s%" + (flowNumLenth < 0 ? "" : "0" + flowNumLenth) + "d",
        orgCode + dateStr, value);
    return test;
  }

  /**
   * 取当前组织代码
   * 
   * @return
   * @throws ServiceException
   */
  private static String getCurrentOrgCode() throws ServiceException {

  }

}
-- sql存储过程
begin  
  declare bExists int;
  
  select count(1) into bExists from wm_sequence where `_name` = in_name;
  if bExists = 0 then 
    INSERT INTO `wm_sequence`(`_name`, `_value`) VALUES (in_name, 0);
  end if;
  
  update wm_sequence SET _value = LAST_INSERT_ID(_value+1) where _name = in_name;
  return (select LAST_INSERT_ID());
end

 

上一篇:出现Could not initialize class net.sf.json.JsonConfig错误。解决方法如下:


下一篇:关于SpringMyBatis常见错误