現(xiàn)在做的項目有一個需求:在不多維護(hù)一張表的情況下,自動生成主鍵,同sequence一樣,而且要有一定的規(guī)范.比如,現(xiàn)在我們的規(guī)范是yymmddhhmmss+四位流水號.沒有辦法,只好對hibernate的主鍵生成做自定義.下面是我的代碼,請多多指教.

聲明,我的hibernate的版本是:hibernate3.2

自定義的時候,只對兩個地方做了修改,一個是自己寫了一個java類,實現(xiàn)了hibernate的IdentifierGenerator和Configurable ,另外一個地方就是對*.hbm.xml文件做修改.
一.
先說對*.hbm.xml做的修改吧,東西比較少.
原始的配置文件中,主鍵生成時,采用的是自動增加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便是自己寫的java類.


二.擴展的java類.實現(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);

    //存儲最大值的數(shù)組的容量
    private static final int MAX_CAPACITY = 2000;

    /**同步鎖*/
    private static final Object lock = new Object();

    //存儲表存儲在數(shù)組中的索引值
    private static Map map = new HashMap();

    //最大值數(shù)組
    private static long[] seqs = new long[MAX_CAPACITY];

    //最大值數(shù)組已經(jīng)使用的容量
    private static int lastIndex;

    //遞增步長,默認(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];
       
        //得到流水號,是自己寫的工具類生成的.形式為000x
        String seqStr = JspFormate.currentFormateORM(seq);
        //得到y(tǒng)ymmdd,是自己寫的方法工具類生成的yymmdd
        String preDate = JspFormate.dateFormateYYYYMMDD(new Date()).substring(2);
        //得到hhmmss,是自己寫的工具類獲取的hhmmss
        String preHour = JspFormate.dateFormateOnlyHHMMSSORM(new Date());

        return preDate + preHour + seqStr;
    }

    /**
     * 找到表中自動增長字段存儲在數(shù)組中的索引值
     * @return 索引值
     */
    private int findIndex() {
        int index = 0;

        //首先中緩存中取出索引值
        Integer integer = (Integer) map.get(key);

        //如果沒有找到就從數(shù)據(jù)庫中讀出最大值并進(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)造存儲在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;
    }
}