首先在開發之中複合主鍵是一中強烈不建議使用的技術,在任何一張數據表裏面如果要設置主鍵應該只設置一個字段,但是複合主鍵畢竟屬於標準的SQL語法,所以在Hibernate或者是JPA之中也都有複合主鍵的定義支持。
範例:數據庫腳本
-- 刪除數據表
DROP TABLE IF EXISTS member;
-- 創建數據表
CREATE TABLE member(
mid VARCHAR(50),
mname VARCHAR(50),
mage INT,
CONSTRAINT pk_mid_name PRIMARY KEY(mid,name)
);
此時設置了兩個主鍵,但是一定要記住一點,主鍵不應該重複,所以在隨後生成Hibernate操作的時候就要觀察它生成類的形式。
1 基於HBM文件的配置
範例:定義MemberId類
@SuppressWarnings("serial")
public class MemberId implements java.io.Serializable {
// Fields
private String mid;
private String mname;
}
爲了能夠確定唯一,在這個MemberId類裏面必須要覆寫equals()和hashCode()兩個方法。
範例:在Member類裏面利用MemberId來描述複合主鍵
@SuppressWarnings("serial")
public class Member implements java.io.Serializable {
// Fields
private MemberId id;
private Integer mage;
}
隨後需要觀察Member.hbm.xml文件的組成。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.lks.pojo.Member" table="member" catalog="hedb">
<!-- 取代的是id元素,表示此時的id是一個複合主鍵 -->
<composite-id name="id" class="org.lks.pojo.MemberId">
<key-property name="mid" type="java.lang.String">
<column name="mid" length="50" />
</key-property>
<key-property name="mname" type="java.lang.String">
<column name="mname" length="50" />
</key-property>
</composite-id>
<property name="mage" type="java.lang.Integer">
<column name="mage" />
</property>
</class>
</hibernate-mapping>
範例:測試代碼
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;
public class TestMemberInsert {
public static void main(String[] args) {
MemberId id = new MemberId();
id.setMid("3161301220");
id.setMname("lks");
Member vo = new Member();
vo.setId(id);
vo.setMage(23);
HibernateSessionFactory.getSession().save(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
insert
into
hedb.member
(mage, mid, mname)
values
(?, ?, ?)
此時信息可以正常保存(複合主鍵不重複)。
當然在進行數據查詢的時候也有一些需要注意的概念,既然ID不能夠重複,所以在數據查詢中使用的get()方法來講就必須考慮到複合主鍵不能重複的特點,所以才覆寫了hashCode()以及equals()方法。
範例:數據查詢
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;
public class TestMemberGet {
public static void main(String[] args) {
MemberId id = new MemberId();
id.setMid("3161301220");
id.setMname("lks");
Member vo = (Member)HibernateSessionFactory.getSession().get(Member.class, id);
System.out.println(vo);
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
select
member0_.mid as mid1_0_0_,
member0_.mname as mname2_0_0_,
member0_.mage as mage3_0_0_
from
hedb.member member0_
where
member0_.mid=?
and member0_.mname=?
org.lks.pojo.Member@3d7fa3ae
所有的類的屬性都會自動的根據配置進行不同類型的關係組成。
2 Annotation配置
雖然複合主鍵出現較少,但是在JPA的開發標準中依然支持了複合主鍵映射,並且這個複合主鍵的映射與之前的細粒度劃分不同,它可以完美的配置。
範例:觀察生成的MemberId程序類
package org.lks.pojo;
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* MemberId entity. @author MyEclipse Persistence Tools
*/
@SuppressWarnings("serial")
@Embeddable
public class MemberId implements java.io.Serializable {
// Fields
private String mid;
private String mname;
// Constructors
/** default constructor */
public MemberId() {
}
/** full constructor */
public MemberId(String mid, String mname) {
this.mid = mid;
this.mname = mname;
}
// Property accessors
@Column(name = "mid", nullable = false, length = 50)
public String getMid() {
return this.mid;
}
public void setMid(String mid) {
this.mid = mid;
}
@Column(name = "mname", nullable = false, length = 50)
public String getMname() {
return this.mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof MemberId))
return false;
MemberId castOther = (MemberId) other;
return ((this.getMid() == castOther.getMid())
|| (this.getMid() != null && castOther.getMid() != null && this.getMid().equals(castOther.getMid())))
&& ((this.getMname() == castOther.getMname()) || (this.getMname() != null
&& castOther.getMname() != null && this.getMname().equals(castOther.getMname())));
}
public int hashCode() {
int result = 17;
result = 37 * result + (getMid() == null ? 0 : this.getMid().hashCode());
result = 37 * result + (getMname() == null ? 0 : this.getMname().hashCode());
return result;
}
}
範例:觀察Member.java類
package org.lks.pojo;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* Member entity. @author MyEclipse Persistence Tools
*/
@SuppressWarnings("serial")
@Entity
@Table(name = "member", catalog = "hedb")
public class Member implements java.io.Serializable {
// Fields
private MemberId id;
private Integer mage;
// Constructors
/** default constructor */
public Member() {
}
/** minimal constructor */
public Member(MemberId id) {
this.id = id;
}
/** full constructor */
public Member(MemberId id, Integer mage) {
this.id = id;
this.mage = mage;
}
// Property accessors
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "mid", column = @Column(name = "mid", nullable = false, length = 50)),
@AttributeOverride(name = "mname", column = @Column(name = "mname", nullable = false, length = 50)) })
public MemberId getId() {
return this.id;
}
public void setId(MemberId id) {
this.id = id;
}
@Column(name = "mage")
public Integer getMage() {
return this.mage;
}
public void setMage(Integer mage) {
this.mage = mage;
}
}
由於有開發工具的支持,使用複合主鍵比較方便。