現(xiàn)在做的項(xiàng)目有一個(gè)需求:在不多維護(hù)一張表的情況下,自動(dòng)生成主鍵,同sequence一樣,而且要有一定的規(guī)范.比如,現(xiàn)在我們的規(guī)范是yymmddhhmmss+四位流水號(hào).沒(méi)有辦法,只好對(duì)hibernate的主鍵生成做自定義.下面是我的代碼,請(qǐng)多多指教.
聲明,我的hibernate的版本是:hibernate3.2
自定義的時(shí)候,只對(duì)兩個(gè)地方做了修改,一個(gè)是自己寫(xiě)了一個(gè)java類(lèi),實(shí)現(xiàn)了hibernate的IdentifierGenerator和Configurable ,另外一個(gè)地方就是對(duì)*.hbm.xml文件做修改.
一.
先說(shuō)對(duì)*.hbm.xml做的修改吧,東西比較少.
原始的配置文件中,主鍵生成時(shí),采用的是自動(dòng)增加1,如下:
<class name="com.ce.fxmgn.entity.Hold" table="HOLD">
<id name="oid" type="java.lang.String">
<column name="OID" length="32" />
<generator class="sequence">
<param name="sequence">seq_id</param>
</generator>
</id>
在修改后,去掉了sequence,如下:
<class name="com.ce.fxmgn.entity.Hold" table="HOLD">
<id name="oid" type="java.lang.String">
<column name="OID" length="32" />
<generator class="com.hello.test.po.InMemoryIncrement">
</generator>
</id>
其中,com.hello.test.po.InMemoryIncrement便是自己寫(xiě)的java類(lèi).
二.擴(kuò)展的java類(lèi).實(shí)現(xiàn)了hibernate的IdentifierGenerator和Configurable
package com.hello.test.po;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.type.Type;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Properties;
public class InMemoryIncrement implements IdentifierGenerator, Configurable {
private static final Log log = LogFactory.getLog(InMemoryIncrement.class);
//存儲(chǔ)最大值的數(shù)組的容量
private static final int MAX_CAPACITY = 2000;
/**同步鎖*/
private static final Object lock = new Object();
//存儲(chǔ)表存儲(chǔ)在數(shù)組中的索引值
private static Map map = new HashMap();
//最大值數(shù)組
private static long[] seqs = new long[MAX_CAPACITY];
//最大值數(shù)組已經(jīng)使用的容量
private static int lastIndex;
//遞增步長(zhǎng),默認(rèn)加1
private int step = 1;
private String key;
private String sql;
private Connection connection;
private Class returnClass;
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
// TODO Auto-generated method stub
connection = session.connection();
long seq = -1;
//找到索引值
int index = findIndex();
//把最大值加1
seqs[index] = seqs[index] + step;
seq = seqs[index];
//得到流水號(hào),是自己寫(xiě)的工具類(lèi)生成的.形式為000x
String seqStr = JspFormate.currentFormateORM(seq);
//得到y(tǒng)ymmdd,是自己寫(xiě)的方法工具類(lèi)生成的yymmdd
String preDate = JspFormate.dateFormateYYYYMMDD(new Date()).substring(2);
//得到hhmmss,是自己寫(xiě)的工具類(lèi)獲取的hhmmss
String preHour = JspFormate.dateFormateOnlyHHMMSSORM(new Date());
return preDate + preHour + seqStr;
}
/**
* 找到表中自動(dòng)增長(zhǎng)字段存儲(chǔ)在數(shù)組中的索引值
* @return 索引值
*/
private int findIndex() {
int index = 0;
//首先中緩存中取出索引值
Integer integer = (Integer) map.get(key);
//如果沒(méi)有找到就從數(shù)據(jù)庫(kù)中讀出最大值并進(jìn)行cache
if (null == integer) {
//double check lock
synchronized (lock) {
integer = (Integer) map.get(key);
if (null == integer) {
long maxvalue = 1;
/* try {
maxvalue = getMaxvalue();
} catch (SQLException e) {
log.error(e);
}*/
maxvalue = new Long(0).longValue();
integer = new Integer(lastIndex++);
seqs[integer.intValue()] = maxvalue;
map.put(key, integer);
}
}
}
index = integer.intValue();
return index;
}
public void configure(Type type, Properties params, Dialect d)
throws MappingException {
// 取出table參數(shù)
String table = params.getProperty("table");
if (table == null) {
table = params.getProperty(PersistentIdentifierGenerator.TABLE);
}
//取出column參數(shù)
String column = params.getProperty("column");
if (column == null) {
column = params.getProperty(PersistentIdentifierGenerator.PK);
}
//表的sehcma參數(shù)
String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
returnClass = type.getReturnedClass();
//取出step參數(shù)
String stepvalue = params.getProperty("step");
if ((null != stepvalue) && !"".equals(stepvalue.trim())) {
try {
step = Integer.parseInt(stepvalue);
} catch (Exception e) {
log.error(e);
}
}
//構(gòu)造存儲(chǔ)在Map中的索引值的key name
key = table + "_$_" + column;
//根據(jù)參數(shù)構(gòu)造取最大值的SQL
sql = "select max(" + column + ") from ";
if (null != schema) {
sql += (schema + ".");
}
sql += table;
}
/**
* 取指定表中id字段的最大值,不存在記錄返回0
* @return 最大值
* @throws SQLException if sql error occurs.
*/
private long getMaxvalue() throws SQLException {
long maxvalue = 0;
PreparedStatement st = connection.prepareStatement(sql);
System.out.println("============================================" + sql);
ResultSet rs = null;
try {
rs = st.executeQuery();
if (rs.next()) {
maxvalue = rs.getLong(1);
}
sql = null;
} finally {
if (rs != null) {
rs.close();
}
st.close();
}
return maxvalue;
}
}