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

原创 2013年12月04日 12:03:00


        昨天在某个网站上(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  {
	
	@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)

可是这个错误在该网站中并没有出现,因为我的配置并没有任何不同,所以我认为是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()方法:

@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,查看数据库信息如下:




Oracle 注解 主键 错误 Unknown integral data type for ids : java.lang.String

这个错误通常是由主键引起的。 当改为uuid后就解决了,原因是native是针对Integer对象的自增是对应数据库中的Integer存入的,而这里,你写个String类型的,它就不认可了! java...
  • nieshanfeng1
  • nieshanfeng1
  • 2015年08月04日 00:38
  • 3073

Unknown integral data type for ids : java.lang.String; nested exception is org.hibernate.id.Identifi

1.发生的异常内容: org.springframework.orm.hibernate5.HibernateSystemException: Unknown integral data type ...
  • qq_27937043
  • qq_27937043
  • 2017年05月14日 19:52
  • 1170

解决weka API读取Oracle10g数据库中date型数据出错问题

系统环境: 操作系统:win10 数据库:Oracle10g weka版本:weka3.8 jdbc:ODBC14.jar 开发软件:MyEclipse2015 Bling 问题描述: 使用weka....
  • u010752600
  • u010752600
  • 2017年06月14日 13:36
  • 323

Python个人学习笔记四

Python个人学习笔记四
  • bjtbjt
  • bjtbjt
  • 2014年09月22日 17:17
  • 3348

WekaAPI的学习(加载数据)

Weka数据加载,由于weka是基于java的因此数据加载相对比较简单上手。
  • zhangyifei521
  • zhangyifei521
  • 2016年06月13日 16:19
  • 2926

绕过WAF的SQL注入语句

0x00前言  现在的网络环境往往是WAF/IPS/IDS保护着Web 服务器等等,这种保护措施往往会过滤挡住我们的SQL注入查询链接,甚至封锁我们的主机IP,所以这个时候,我们就要考虑怎样进行绕过,...
  • qq_29277155
  • qq_29277155
  • 2016年05月03日 16:46
  • 12980

iOS开发,导入c文件引发的 Unknown type name 'NSString' 问题

摘要:今天看到个问题,编辑工程提示Unknowntypename'NSString',如下图导致出现异常的原因是是因为工程中添加了ZipArchive(第三方开源解压缩库)一般情况下出现“Unknow...
  • Bruce__Liu
  • Bruce__Liu
  • 2015年07月22日 14:07
  • 4651

从DB::到C::看dz2.5的变革--Discuz…

前言:本文对普通的dz使用用户或者站长帮助不大,因为这部分朋友只需要关注功能上面的变化,无需知道底层代码结构的事情,请忽略跳过。 如果是已经或者想要对dz进行二次开发或者组件开发的朋友们应该有所体会...
  • accress
  • accress
  • 2013年12月26日 14:36
  • 512

caffe增加自己的layer实战(下-续1)--caffe学习(13)

接上篇:caffe增加自己的layer实战(下)–caffe学习(12) 构造完函数后我们就要进入proto目录。编辑caffe.proto文件,构造我们的video_data_layer的输入参数...
  • u014381600
  • u014381600
  • 2017年01月09日 15:49
  • 1289

关于C语言中的 " 类型提升 "(type promotion)

看 Expert C Programming 看到了关于C语言中“类型提升”的详细说明, Type conversions in C are much more widespread than ...
  • xuzhezhaozhao
  • xuzhezhaozhao
  • 2013年07月10日 11:22
  • 2344
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hibernate如何自定义自增长的主键值?
举报原因:
原因补充:

(最多只允许输入30个字)