Hibernate的開發之中主要分爲兩種模式:一種是基於*.hbm.xml
文件的、另外一種是基於Annotation的配置,容器映射技術最早的時候出現在Hibernate時期,但是後來由於JPA的標準裏面沒有定義容器映射技術的相關操作,所以現在的開發之中已經很少再去使用容器映射。
Hibernate中主要分爲如下三種容器映射:
(1)Set容器映射:不能夠保存重複數據;
(2)List容器映射:可以保存重複數據,但是它爲了區分唯一,需要設置一個單獨的索引編號;
(3)Map容器映射:是保存key和value兩個數據。
所有的容器映射技術都要求其在兩張數據表中進行操作。
1 Set容器映射
Set容器映射主要是可以保存簡單的一對多關係,例如:在之前曾經實現過這樣一個功能:利用轉換器實現了一個用戶可以保存有多個email地址的信息,但是之前的做法比較複雜,而如果使用Set容器映射就可以利用兩張表的關係來描述。
範例:數據庫腳本
-- 刪除數據表
DROP TABLE IF EXISTS member;
DROP TABLE IF EXISTS email;
-- 創建數據表
CREATE TABLE member(
mid VARCHAR(50),
mname VARCHAR(50),
CONSTRAINT pk_mid PRIMARY KEY(mid)
);
CREATE TABLE email(
mid VARCHAR(50),
etitle VARCHAR(50),
CONSTRAINT fk_email_member FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE CASCADE
);
由於一個用戶可以有多個email地址,所以在email表中定義外鍵的時候並沒有設置唯一約束。
範例:修改Member.java類
package org.lks.pojo;
import java.util.HashSet;
import java.util.Set;
@SuppressWarnings("serial")
public class Member implements java.io.Serializable {
// Fields
private String mid;
private String mname;
private Set<String> emails = new HashSet<String>();
// Constructors
/** default constructor */
public Member() {
}
/** minimal constructor */
public Member(String mid) {
this.mid = mid;
}
// Property accessors
public String getMid() {
return this.mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getMname() {
return this.mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public Set<String> getEmails() {
return this.emails;
}
public void setEmails(Set<String> emails) {
this.emails = emails;
}
}
一個用戶有多個email地址,但是由於此時的email只有唯一的一個字段(不去考慮mid這個外鍵的關係)。
範例:手工維護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 name="mid" type="java.lang.String">
<column name="mid" length="50" />
<generator class="assigned"></generator>
</id>
<property name="mname" type="java.lang.String">
<column name="mname" length="50" />
</property>
<!-- 容器映射之中emails這個集合的操作對應的是email數據表 -->
<set name="emails" table="email">
<key><!-- email與member表的關聯靠的是mid這個外鍵 -->
<column name="mid" length="50" />
</key>
<!-- 在進行集合操作的時候email表裏面對應的title屬性操作 -->
<element type="java.lang.String" column="etitle"/>
</set>
</class>
</hibernate-mapping>
隨後如果進行保存或者更新等操作的時候會自動將Set集合中的數據同步到email表中的etitle字段中,同時外鍵數據會自動進行維護。
範例:增加數據
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberInsert {
public static void main(String[] args) {
Member vo = new Member();
vo.setMid("3161301220");
vo.setMname("lks");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
HibernateSessionFactory.getSession().save(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
insert
into
hedb.member
(mname, mid)
values
(?, ?)
Hibernate:
insert
into
email
(mid, etitle)
values
(?, ?)
Hibernate:
insert
into
email
(mid, etitle)
values
(?, ?)
此時發現在進行數據增加的過程之中,用戶實際上只是進行了Member對象的操作,但是同時會根據自身的配置文件自動進行email數據表的操作,同時這個外鍵關係也自動設置上。
範例:數據更新——不會去考慮持久態下的數據更新
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberInsert {
public static void main(String[] args) {
Member vo = new Member();
vo.setMid("3161301220");
vo.setMname("lks");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
HibernateSessionFactory.getSession().update(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
update
hedb.member
set
mname=?
where
mid=?
Hibernate:
delete
from
email
where
mid=?
Hibernate:
insert
into
email
(mid, etitle)
values
(?, ?)
Hibernate:
insert
into
email
(mid, etitle)
values
(?, ?)
Hibernate:
insert
into
email
(mid, etitle)
values
(?, ?)
首先在此處先刪除掉了email表中已有的對應數據,而後重新進行數據的保存操作。
範例:數據刪除
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberInsert {
public static void main(String[] args) {
Member vo = new Member();
vo.setMid("3161301220");
HibernateSessionFactory.getSession().delete(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
select
member_.mid,
member_.mname as mname2_0_
from
hedb.member member_
where
member_.mid=?
Hibernate:
delete
from
email
where
mid=?
Hibernate:
delete
from
hedb.member
where
mid=?
如果現在使用delete()方法進行數據刪除的話,那麼會首先查詢出所有的數據,而後執行兩個刪除,一個是刪除email子表數據,另外一個刪除對應的member的父表數據。但是從實際的角度來看,如果真進行數據的刪除肯定使用Query接口完成,但是如果使用Query接口又會如何?
範例:數據刪除
package org.lks.test;
import org.hibernate.Query;
import org.lks.dbc.HibernateSessionFactory;
public class TestMemberDeleteQuery {
public static void main(String[] args) {
Query query = HibernateSessionFactory.getSession().createQuery("DELETE FROM Member WHERE mid=?");
query.setParameter(0, "3161301220");
query.executeUpdate();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
delete
from
hedb.member
where
mid=?
此時的程序只發出了刪除member表數據的一個刪除指令,這樣如果要想刪除子表,就只能夠依靠外鍵的級聯刪除完成了。
比較:關於delete()與Query刪除的區別?
(1)delete()刪除的時候會考慮到數據關係的維護,會首先發出查詢,而後先刪除子表再刪除父表,但是這樣的刪除太麻煩;
(2)Query刪除只是刪除一張表數據,不關心數據關聯的維護。
2 List容器映射
List容器映射與Set容器映射的最大區別只有一個:List中可以保存有重複數據,而Set不允許有重複。但是千萬要記住一點,List之所以能有重複,是因爲List裏面會自動維護一個索引關係,所以List集合裏面纔可以使用get()根據索引取出數據。
範例:數據庫創建腳本
-- 刪除數據表
DROP TABLE IF EXISTS member;
DROP TABLE IF EXISTS email;
-- 創建數據表
CREATE TABLE member(
mid VARCHAR(50),
mname VARCHAR(50),
CONSTRAINT pk_mid PRIMARY KEY(mid)
);
CREATE TABLE email(
mid VARCHAR(50),
foot INT,
etitle VARCHAR(50),
CONSTRAINT fk_email_member FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE CASCADE
);
此時的foot
字段描述的是List集合中的索引數值。
(1)索引【foot】 = 0
、內容 = [email protected]
;
(2)索引 【foot】= 1
、內容 = [email protected]
;
範例:修改Member.java類
package org.lks.pojo;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("serial")
public class Member implements java.io.Serializable {
// Fields
private String mid;
private String mname;
private List<String> emails = new ArrayList<String>();
public List<String> getEmails() {
return this.emails;
}
public void setEmails(List<String> emails) {
this.emails = emails;
}
}
範例:修改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 name="mid" type="java.lang.String">
<column name="mid" length="50" />
<generator class="assigned"></generator>
</id>
<property name="mname" type="java.lang.String">
<column name="mname" length="50" />
</property>
<list name="emails" table="email" catalog="hedb">
<key><!-- email與member表的關聯靠的是mid這個外鍵 -->
<column name="mid" length="50" />
</key>
<!-- 負責處理數據的索引數值 -->
<index column="foot"/>
<element type="java.lang.String" column="etitle"/>
</list>
</class>
</hibernate-mapping>
範例:增加操作
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberInsert {
public static void main(String[] args) {
Member vo = new Member();
vo.setMid("3161301220");
vo.setMname("lks");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
vo.getEmails().add("[email protected]");
HibernateSessionFactory.getSession().save(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
insert
into
hedb.member
(mname, mid)
values
(?, ?)
Hibernate:
insert
into
hedb.email
(mid, foot, etitle)
values
(?, ?, ?)
Hibernate:
insert
into
hedb.email
(mid, foot, etitle)
values
(?, ?, ?)
Hibernate:
insert
into
hedb.email
(mid, foot, etitle)
values
(?, ?, ?)
Hibernate:
insert
into
hedb.email
(mid, foot, etitle)
values
(?, ?, ?)
此時重複的數據的確進行了有效的保存,但是發現不同數據之中的foot
字段的內容是不同的。
3 Map容器映射
既然說到了Map映射,那麼很明顯,與List或Set最大的不同一定是在子表裏面要保存有key和value兩個數據,所以首先必須對數據表結構進行修改。
範例:數據庫腳本
-- 刪除數據表
DROP TABLE IF EXISTS member;
DROP TABLE IF EXISTS email;
-- 創建數據表
CREATE TABLE member(
mid VARCHAR(50),
mname VARCHAR(50),
CONSTRAINT pk_mid PRIMARY KEY(mid)
);
CREATE TABLE email(
mid VARCHAR(50),
etitle VARCHAR(50),
ealias VARCHAR(50),
CONSTRAINT fk_email_member FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE CASCADE
);
每一個email地址都做一個備註的操作信息。
範例:進行Member.java的修改
package org.lks.pojo;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("serial")
public class Member implements java.io.Serializable {
// Fields
private String mid;
private String mname;
private Map<String,String> emails = new HashMap<String,String>();
public Map<String,String> getEmails() {
return this.emails;
}
public void setEmails(Map<String,String> emails) {
this.emails = emails;
}
}
隨後現在還需要找到Member.hbm.xml文件進行對應的修改操作。
範例:修改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 name="mid" type="java.lang.String">
<column name="mid" length="50" />
<generator class="assigned"></generator>
</id>
<property name="mname" type="java.lang.String">
<column name="mname" length="50" />
</property>
<map name="emails" table="email" catalog="hedb">
<key>
<column name="mid" length="50"/>
</key>
<!-- 描述Map集合中的key對應的數據關係 -->
<map-key type="java.lang.String" column="etitle"/>
<!-- 描述Map集合中的value對應的數據關係 -->
<element type="java.lang.String" column="ealias"/>
</map>
</class>
</hibernate-mapping>
範例:測試數據增加
package org.lks.test;
import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
public class TestMemberInsert {
public static void main(String[] args) {
Member vo = new Member();
vo.setMid("3161301220");
vo.setMname("lks");
vo.getEmails().put("[email protected]","工作郵箱1");
vo.getEmails().put("[email protected]","工作郵箱2");
vo.getEmails().put("[email protected]","個人郵箱");
vo.getEmails().put("[email protected]","家庭郵箱");
HibernateSessionFactory.getSession().save(vo);
HibernateSessionFactory.getSession().beginTransaction().commit();
HibernateSessionFactory.closeSession();
System.exit(0);
}
}
Hibernate:
insert
into
hedb.member
(mname, mid)
values
(?, ?)
Hibernate:
insert
into
hedb.email
(mid, etitle, ealias)
values
(?, ?, ?)
Hibernate:
insert
into
hedb.email
(mid, etitle, ealias)
values
(?, ?, ?)
在進行email數據保存的過程之中,也是自動維護了key(etitle列)與value(ealias列)的數據。