本想利用Hibernate的JPA方式(不想采用数据库的方式,而是在程序代码中想办法设定),
寻找一种在调用save方法时可以自动生成流水号(8位日期+6位自增长号)作为主键。
但是在研究了Hibernate主键生成策略和Hibernate自定义主键后,
采用JPA注解的形式,自己写生成器来实现org.hibernate.id.Configurable和org.hibernate.id.IdentifierGenerator
两接口的generate 和configure方法,在hbm.xml中可以实现,但是在JPA方式下目前无法实现。

后来,决定用JPA的assigned策略,在save之前程序手动创建流水号id。
那么创建的这个流水号,每天后6位自增长都要从1开始,并且不能有重复。
考虑到并发,不记录产生的流水号最大值,而是记录自增长个数。

思路:1.数据库中创建两张表,一个是定义序列规则的,记录系统所有的序列,因为系统中可能需要“8位日期+6位自增长”这样的序列,
        还可能需要“字母+日期”这样的序列;
        另一个是记录自增长最大值的表,记录 当天自增长的最大值,初始为1;
      2.程序每要创建流水号ID时,
        首先将数据库中系统时间和最后更新时间比较,如果相等,则将最大值字段+1;否则置1;最后更新时间更新为当前时间;
        然后取出最大值,作为自增长部分的内容,再和日期拼接,即可产生流水号ID。
       

1.首先定义序列号规则
INSERT INTO SYS_NUMBS(NUMBER_ID, NUMBER_NAME, DESCRIPTION, FORMULAE)
VALUES(4, '投诉建议流水号', '8位日期+6位流水号', 'YYYYMMDD######')
;
2.创建记录自增长最大值的表
CREATE TABLE SYS_SEQ_MAX (
 NUMBER_ID NUMBER(15,5) NOT NULL PRIMARY KEY,
 MAX_NO       NUMBER(15,5) NULL,
        LAST_DATE      DATE NULL
 );

//更新并得到即将产生的序列号的自增长部分

 public int updateAndGetCurrentSeq(int numberId) {

  StringBuffer updateHql = new StringBuffer(
    "update Sys_Seq_Max set "
      + "max_No = (case when to_char(last_Date,'yyyyMMdd')=to_char(sysdate,'yyyyMMdd') then max_No + 1 "
      + "else 1 end ),last_date = sysdate where 1=1 and number_Id = :numberId");

  // 更新SysSeqMax表中的相关记录

  Query query = this.getSession().createSQLQuery(updateHql.toString());
  query.setParameter("numberId", new Integer(numberId));

  int updateRows = query.executeUpdate();

  /* 得到当前的序列号 start */
  SysSeqMax sysSeqMax = (SysSeqMax) this.get(SysSeqMax.class,
    new Integer(numberId));

  int currentNumb = -1;
  if (sysSeqMax == null) {
   // 表中没有相应记录,则生成一条,序列号为1
   currentNumb = 1;
   sysSeqMax = new SysSeqMax();
   sysSeqMax.setNumberId(numberId);
   sysSeqMax.setMaxNo(currentNumb);
   sysSeqMax.setLastDate(new Date());
   this.save(sysSeqMax);
  } else {
   if (updateRows == 0) {// 更新的行数为0,表示序列号没有更新

    currentNumb = 1;
    sysSeqMax.setNumberId(numberId);
    sysSeqMax.setMaxNo(currentNumb);
    sysSeqMax.setLastDate(new Date());
    this.save(sysSeqMax);
   }
   // 表中有记录,就得到序列号
   currentNumb = sysSeqMax.getMaxNo();
  }

  // 不加这段的话在同一session中调用该方法批量生成同类序列号时会返回一样的序列号

  this.getHibernateTemplate().flush();
  this.getHibernateTemplate().evict(sysSeqMax);

  if (currentNumb == -1) {
   throw new DAOException("错误的顺序号");
  }
  /* 得到当前的序列号 end */
  return currentNumb;
 }

然后再和日期拼接