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列)的数据。