昨天在某个网站上(http://sunny.blog.51cto.com/182601/31605)看到关于自定义增长的sequence主键值的定义,之所以会有自定义主键的原因是希望通过自定义自增长的主键值到达数据库中的表的主键使用的是前缀字符 + 序列。也就是说我们每个对象的主键值都不是纯数字。那么hibernate怎样将这个主键写入数据库呢。
通过阅读该网站可以知道,对于这种特殊的要求,hibernate本身并没有提供这种主键生成策略。而hibenate的帮助手册中也提到:
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 {
@Override
public 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)
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 "
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()方法:
@Override
public 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 {
@Override
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
Serializable s = super.generate(session, object);
System.out.println(s);
return s+"a";
}
@Override
public void configure(Type type, Properties params, Dialect dialect)
throws MappingException {
super.configure(new IntegerType(), params, dialect);
}
}
此时,再次运行程序一切ok,查看数据库信息如下: