本想利用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;
}
然后再和日期拼接