基于业务需求,您会需要使用两个字段来作复合主键,例如在User数据表中,您也许会使用"name"与"phone"两个字段来定义复合主键。
假设您这么建立User表格:
CREATE
TABLE
user
( name
VARCHAR
(
100
)
NOT
NULL
, phone
VARCHAR
(
50
)
NOT
NULL
, age
INT
,
PRIMARY
KEY
(name, phone) );
在表格中,"name"与"age"被定义为复合主键,在映像时,您可以让User类别直接带有"name"与"age"这两个属性,而Hibernate要求复合主键类别要实作Serializable接口,并定义equals()与hashCode()方法:
User.java
package
onlyfun.caterpillar;
import
java.io.Serializable;
import
org.apache.commons.lang.builder.EqualsBuilder;
import
org.apache.commons.lang.builder.HashCodeBuilder;
//
复合主键类的对应类别必须实作Serializable接口
public
class
User
implements
Serializable {
private
String name;
private
String phone;
private
Integer age;
public
User() { }
public
Integer getAge() {
return
age; }
public
void
setAge(Integer age) {
this
.age
=
age; }
public
String getName() {
return
name; }
public
void
setName(String name) {
this
.name
=
name; }
public
String getPhone() {
return
phone; }
public
void
setPhone(String phone) {
this
.phone
=
phone; }
//
必须重新定义equals()与hashCode()
public
boolean
equals(Object obj) {
if
(obj
==
this
) {
return
true
; }
if
(
!
(obj
instanceof
User)) {
return
false
; } User user
=
(User) obj;
return
new
EqualsBuilder() .append(
this
.name, user.getName()) .append(
this
.phone, user.getPhone()) .isEquals(); }
public
int
hashCode() {
return
new
HashCodeBuilder() .append(
this
.name) .append(
this
.phone) .toHashCode(); } }
equals()与hashCode()方法被用作两笔不同数据的识别依据;接着您可以使用<composite-id>在映射文件中定义复合主键与对象的属性对应:
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="user">
<composite-id>
<key-property name="name" column="name" type="java.lang.String"/>
<key-property name="phone" column="phone" type="java.lang.String"/>
</composite-id>
<property name="age" column="age" type="java.lang.Integer"/>
</class>
</hibernate-mapping>
在储存数据方面,复合主键的储存没什么区别,现在的问题在于如何依据复合主键来查询数据,例如使用load()方法,您可以创建一个User实例,并设定复合主键对应的属性,接着再透过load()查询对应的数据,例如:
User user
=
new
User(); user.setName(
"
bush
"
); user.setPhone(
"
0970123456
"
); Session session
=
sessionFactory.openSession();
//
以实例设定复合主键并加载对应的数据
user
=
(User) session.load(User.
class
, user); System.out.println(user.getAge()
+
"
/t
"
+
user.getName()
+
"
/t
"
+
user.getPhone()); session.close();
可以将主键的信息独立为一个类别,例如:
UserPK.java
package
onlyfun.caterpillar;
import
java.io.Serializable;
import
org.apache.commons.lang.builder.EqualsBuilder;
import
org.apache.commons.lang.builder.HashCodeBuilder;
public
class
UserPK
implements
Serializable {
private
String name;
private
String phone;
public
String getName() {
return
name; }
public
void
setName(String name) {
this
.name
=
name; }
public
String getPhone() {
return
phone; }
public
void
setPhone(String phone) {
this
.phone
=
phone; }
public
boolean
equals(Object obj) {
if
(obj
==
this
) {
return
true
; }
if
(
!
(obj
instanceof
User)) {
return
false
; } UserPK pk
=
(UserPK) obj;
return
new
EqualsBuilder() .append(
this
.name, pk.getName()) .append(
this
.phone, pk.getPhone()) .isEquals(); }
public
int
hashCode() {
return
new
HashCodeBuilder() .append(
this
.name) .append(
this
.phone) .toHashCode(); } }
现在User类别的主键信息被分离出来了,例如:
User.java
package
onlyfun.caterpillar;
import
java.io.Serializable;
public
class
User
implements
Serializable {
private
UserPK userPK;
//
主键
private
Integer age;
public
User() { }
public
UserPK getUserPK() {
return
userPK; }
public
void
setUserPK(UserPK userPK) {
this
.userPK
=
userPK; }
public
Integer getAge() {
return
age; }
public
void
setAge(Integer age) {
this
.age
=
age; } }
在映像文件方面,需要指定主键类的信息,例如:
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="user">
<composite-id name="userPK" class="onlyfun.caterpillar.UserPK" unsaved-value="any">
<key-property name="name" column="name" type="java.lang.String"/>
<key-property name="phone" column="phone" type="java.lang.String"/>
</composite-id>
<property name="age" column="age" type="java.lang.Integer"/>
</class>
</hibernate-mapping>
在查询数据时,必须指定主键信息,例如:
UserPK pk
=
new
UserPK(); pk.setName(
"
bush
"
); pk.setPhone(
"
0970123456
"
); Session session
=
sessionFactory.openSession();
//
以主键类实例设定复合主键并加载对应的数据
User user
=
(User) session.load(User.
class
, pk); System.out.println(user.getAge()
+
"
/t
"
+
user.getUserPK().getName()
+
"
/t
"
+
user.getUserPK().getPhone()); session.close();