现在做的项目有一个需求:在不多维护一张表的情况下,自动生成主键,同sequence一样,而且要有一定的规范.比如,现在我们的规范是yymmddhhmmss+四位流水号.没有办法,只好对hibernate的主键生成做自定义.下面是我的代码,请多多指教.

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

自定义的时候,只对两个地方做了修改,一个是自己写了一个java类,实现了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类.实现了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 );

    
// 存储最大值的数组的容量 
     private   static   final   int  MAX_CAPACITY  =   2000 ;

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

    
// 存储表存储在数组中的索引值 
     private   static  Map map  =   new  HashMap();

    
// 最大值数组 
     private   static   long [] seqs  =   new   long [MAX_CAPACITY];

    
// 最大值数组已经使用的容量 
     private   static   int  lastIndex;

    
// 递增步长,默认加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);
        
// 得到yymmdd,是自己写的方法工具类生成的yymmdd
        String preDate  =  JspFormate.dateFormateYYYYMMDD( new  Date()).substring( 2 );
        
// 得到hhmmss,是自己写的工具类获取的hhmmss
        String preHour  =  JspFormate.dateFormateOnlyHHMMSSORM( new  Date());

        
return  preDate  +  preHour  +  seqStr;
    }

    
/**
     * 找到表中自动增长字段存储在数组中的索引值
     * 
@return  索引值
     
*/
    
private   int  findIndex() {
        
int  index  =   0 ;

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

        
// 如果没有找到就从数据库中读出最大值并进行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参数 
        String table  =  params.getProperty( " table " );

        
if  (table  ==   null ) {
            table 
=  params.getProperty(PersistentIdentifierGenerator.TABLE);
        }

        
// 取出column参数 
        String column  =  params.getProperty( " column " );

        
if  (column  ==   null ) {
            column 
=  params.getProperty(PersistentIdentifierGenerator.PK);
        }

        
// 表的sehcma参数 
        String schema  =  params.getProperty(PersistentIdentifierGenerator.SCHEMA);

        returnClass 
=  type.getReturnedClass();

        
// 取出step参数 
        String stepvalue  =  params.getProperty( " step " );

        
if  (( null   !=  stepvalue)  &&   ! "" .equals(stepvalue.trim())) {
            
try  {
                step 
=  Integer.parseInt(stepvalue);
            } 
catch  (Exception e) {
                log.error(e);
            }
        }

        
// 构造存储在Map中的索引值的key name 
        key  =  table  +   " _$_ "   +  column;

        
// 根据参数构造取最大值的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;
    }
}