在Hibernate中兑现自己的主键生成器(id Generator)
Hibernate提供了很多内置的Generator,能很好的满足大多数的应用场景。但开发者可以选择提供自己特定的Generator实现,以满足自己的特定需求——如用更有意义的字符串类型的主键代替整型主键。我们考虑假设有一个user表,主键字段的值我更希望看到的是类似于“U1,U2,U3…”这样更有意义的主键,而不是简单的“1,2,3…”。在数据库中存在大量表,并且表之间的关系较为复杂的情况下,使用有意义的字符串类型的主键能使开发者对表之间的关系更一目了然。
我希望该Generator具有以下功能:
1、 生成的主键是字符串类型。
2、 前缀英文字母或单词可以在配置文件中任意设置。
3、 前缀后面的数字自动增加。
为了实现上述功能,我查看了一下Hibernate所提供的内置的Generator,其中的“hilo”与我要实现的功能较为接近,只不过它返回的是long,short或int,而不是String。看来可以对它稍加改造,于是查看了它的源代码:org.hibernate.id.TableHiLoGenerator。大家可以自己看一下,我就不帖出来了。根据TableHiLoGenerator,很快就完成了我自己的MyGenerator。代码如下:
- package com.mytest.hibernate.util;
- import java.util.Properties;
- import java.io.Serializable;
- import org.hibernate.dialect.Dialect;
- import org.hibernate.HibernateException;
- import org.hibernate.engine.SessionImplementor;
- import org.hibernate.id.*;
- import org.hibernate.type.*;
- import org.hibernate.util.PropertiesHelper;
- public class MyGenerator extends TableGenerator{
- public static final String PREFIX = "prefix";
- private String prefix;
- public void configure(Type type, Properties params, Dialect d) {
- super.configure(type, params, d);
- prefix=PropertiesHelper.getString(PREFIX,params,"");
- }
- public synchronized Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
- int val = ( (Integer) super.generate(session, obj) ).intValue();
- return prefix+val;
- }
- }
我只是增加了一个prefix,该前缀的值可以在配置文件中任意指定。下面看看怎样具体使用该Generator:
第一步,在数据库中增加一个表key_generator,在该表中增加一个字段user_id,该字段的类型为Integer,并给该字段一个初始值1。
第二步,写User.hbm.xml配置文件
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping package="com.mytest.hibernate.entity.user">
- <class name="User" table="user">
- <id name="userId" type="string" column="USER_ID_">
- <generator class="com.mytest.hibernate.util.MyGenerator">
- <param name="table">key_generator</param>
- <param name="column">user_id</param>
- <param name="prefix">U</param>
- </generator>
- </id>
- …
- </class>
- </hibernate-mapping>
<o:p></o:p>
注意:MyGenerator扩展了TableGenerator类,TableGenerator类由Hibernate提供,它会根据key_generator表中的user_id字段的值来产生下一个整形值。这样我们就得到了“U1,U2,U3,…”主键。
如果我们另外有一个department表,希望产生“D1,D2,D3,…”主健。只需在key_generator表中增加一个整型字段department_id,并给该字段一个初始值1。Department.hbm.xml如下:
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping package="com.mytest.hibernate.entity.department">
- <class name="Department" table="department">
- <id name="departmentId" type="string" column="DEPARTMENT_ID_">
- <generator class="com.mytest.hibernate.util.MyGenerator">
- <param name="table">key_generator</param>
- <param name="column">department_id</param>
- <param name="prefix">D</param>
- </generator>
- </id>
- …
- </class>
- </hibernate-mapping>
<hibernate-mapping>
<class name="member.Member" table="MEMBER" schema="DEVELOPER">
<id name="memberid" type="java.lang.String">
<column name="MEMBERID" length="8" />
<generator class="com.underset.key_strategy.MyGenerator">
<param name="table">key_generator</param>
<param name="column">MEMBERID</param>
<param name="prefix">U</param>
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="30" not-null="true" />
</property>
</class>
</hibernate-mapping>
却跳出这个错:
2008-08-28 23:47:54,693 ERROR [org.hibernate.id.TableGenerator] - could not read a hi value
java.sql.SQLException: ORA-00942: 表或视图不存在