hibernate如何自定义自增长的主键值?

来源:互联网 发布:javascript常用对象 编辑:程序博客网 时间:2024/06/05 09:06


        昨天在某个网站上(http://sunny.blog.51cto.com/182601/31605)看到关于自定义增长的sequence主键值的定义,之所以会有自定义主键的原因是希望通过自定义自增长的主键值到达数据库中的表的主键使用的是前缀字符 + 序列。也就是说我们每个对象的主键值都不是纯数字。那么hibernate怎样将这个主键写入数据库呢。

       通过阅读该网站可以知道,对于这种特殊的要求,hibernate本身并没有提供这种主键生成策略。而hibenate的帮助手册中也提到:

所有的主键生成器都实现org.hibernate.id.IdentifierGenerator 接口。这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当时如果我们直接实现该接口就会十分的麻烦,于是,在该网站中使用的使用的是通过继承import org.hibernate.id.SequenceGenerator类并重写generate方法来实现。如下是我的domain对象的配置信息:

package com.lgh.hibernate.mode;public class SequenceTest {private String id;private String name;package com.lgh.hibernate.mode;public class SequenceTest {private String id;private String name;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}}

SequenceTest.hbm.xml文件配置信息如下:

<class name="SequenceTest" table="t_seq"><id name="id" type="java.lang.String">            <column name="USERID" length="20" />            <generator class="com.lgh.hibernate.mode.IdGenerator">  --》自定义生成器                <param name="sequence">s_userid</param>  --》表示数据库生成的序列名            </generator>          </id><property name="name"/></class>

此为我自定义的主键生成器:


public class IdGenerator extends SequenceGenerator  {@Overridepublic Serializable generate(SessionImplementor session, Object object)throws HibernateException {Serializable s = super.generate(session, object);System.out.println(s);return s+"a";}



本以为一切是如此的easy,没想到我运行的时候出现了如下错误:


Exception in thread "main" org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String         报的错误是Stirng是不能识别的集成的数据类型。at org.hibernate.id.IdentifierGeneratorHelper.getIntegralDataTypeHolder(IdentifierGeneratorHelper.java:178)at org.hibernate.id.SequenceGenerator.buildHolder(SequenceGenerator.java:142)at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:115)at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:105)at com.lgh.hibernate.mode.IdGenerator.generate(IdGenerator.java:19)at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)

可是这个错误在该网站中并没有出现,因为我的配置并没有任何不同,所以我认为是hibernate版本的问题,我的hibernate版本是3.5.5,而该网站中的hibernate版本是3.0.所以才会出现如上错误。于是我经过错误堆栈信息,找到了getIntegralDataTypeHolder方法,该方法定义如下:

    public static IntegralDataTypeHolder getIntegralDataTypeHolder(Class integralType) {        if ( integralType == Long.class                || integralType == Integer.class                || integralType == Short.class ) {            return new BasicHolder( integralType );        }        else if ( integralType == BigInteger.class ) {            return new BigIntegerHolder();        }        else if ( integralType == BigDecimal.class ) {            return new BigDecimalHolder();        }        else {            throw new IdentifierGenerationException(                    "Unknown integral data type for ids : " + integralType.getName()            );        }

原来,该只能识别Integer,Long,Short,BigInteger,BigDecimal类型,而对于其他类型(String)类型,他就会抛出:

"Unknown integral data type for ids "

继续查看堆栈信息,但是并没有找到任何直接相关的信息,但是在SequenceGenerator的初始化的时候会对hbm.xml中的配置进行config:也就是会调用SeequenceGenerator中的config()方法:

public void configure(Type type, Properties params, Dialect dialect) throws MappingException {  type表示hbm.xml配置文件中的id的数据类型ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );sequenceName = normalizer.normalizeIdentifierQuoting(PropertiesHelper.getString( SEQUENCE, params, "hibernate_sequence" ));parameters = params.getProperty( PARAMETERS );if ( sequenceName.indexOf( '.' ) < 0 ) {final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );sequenceName = Table.qualify(dialect.quote( catalogName ),dialect.quote( schemaName ),dialect.quote( sequenceName ));}else {// if already qualified there is not much we can do in a portable manner so we pass it// through and assume the user has set up the name correctly.}this.identifierType = type;  type表示hbm.xml配置文件中的id的数据类型sql = dialect.getSequenceNextValString( sequenceName );}

其中,他会读取hbm.xml文件中的id的type属性,而之间调用的 getIntegralDataTypeHolder()方法中就会去判断该type属性是否符合序列的要求:

因此,为了让String类型能够识别,我们在自定定义的IdGenerator中重写了父类SequenceGenerator中的configure()方法:

@Overridepublic void configure(Type type, Properties params, Dialect dialect)throws MappingException {super.configure(new IntegerType(), params, dialect);}

其中,我将Type类型默认指定为IntegerType类型,所以hibernate对hbm.xml文件中的id的type类型不会再接受审查,这样,就不在报错了。此时我的IdGenerator类完整代码如下:

package com.lgh.hibernate.mode;import java.io.Serializable;import java.util.Properties;import org.hibernate.HibernateException;import org.hibernate.MappingException;import org.hibernate.dialect.Dialect;import org.hibernate.engine.SessionImplementor;import org.hibernate.id.SequenceGenerator;import org.hibernate.type.IntegerType;import org.hibernate.type.Type;public class IdGenerator extends SequenceGenerator  {@Overridepublic Serializable generate(SessionImplementor session, Object object)throws HibernateException {Serializable s = super.generate(session, object);System.out.println(s);return s+"a";}@Overridepublic void configure(Type type, Properties params, Dialect dialect)throws MappingException {super.configure(new IntegerType(), params, dialect);}}

此时,再次运行程序一切ok,查看数据库信息如下:




原创粉丝点击