第十一章 Hibernate容器映射技术
在Hibernate之中所谓的所谓的容器映射技术指的是一种简单的一对多关系,但是这个时候表示多的一方只有一个或两个字段的数据表(不包含外键字段),容器映射技术一共存在五中:set、List、Map、Array、Bag。
11.1、Set映射
如果要想表示出set映射的特点,那么肯定需要两张数据表完成,例如:一个人有多个Email地址,如果说发现采用自定义数据类型的处理很麻烦,那么就可以回归到两张数据表的定义结构上。
范例:数据库创建脚本
-- 使用数据库 USE mldn ; -- 删除数据表 DROP TABLE email ; DROP TABLE member ; -- 创建数据表 CREATE TABLE member( mid VARCHAR(50) , name VARCHAR(50) , CONSTRAINT pk_mid PRIMARY KEY(mid) ) ; CREATE TABLE email( mid VARCHAR(50) , title VARCHAR(200) , CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE CASCADE ) ; |
此时存在了以上的数据表,很明显,每一个人员的email地址是是不可能有重复的,所以此时的映射使用Set集合会更加合适一些。
但是在Myeclipse之中,如果要想创建Hibernate映射,那么是不可能直接通过工具创建的,默认的支持是一对多的支持,所以此处只能够根据member表创建Hibernate映射。
范例:观察Member.java类
package cn.cgj.pojo; import java.util.HashSet; import java.util.Set; @SuppressWarnings("serial") public class Member implements java.io.Serializable { private String mid; private String name; @SuppressWarnings("rawtypes") private Set emails = new HashSet(0); public Member() { } //setter、getter略 } |
虽然在Member类中存在了set集合,但是在Member.hbm.xml文件中发现还不是正常所希望的Set映射。
范例:修改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"> <hibernate-mapping> <class name="cn.cgj.pojo.Member" table="member" catalog="mldn"> <id name="mid" type="java.lang.String"> <column name="mid" length="50" /> <generator class="assigned"></generator> </id> <property name="name" type="java.lang.String"> <column name="name" length="50" /> </property> <set name="emails" table="email" lazy="false"> <key> <column name="mid" length="50" /> </key> <element type="cn.cgj.pojo.Email" column="title"/> </set> </class> </hibernate-mapping> |
此时“<set>”配置所表示的含义是,集合之中对应的数据要通过email表取得,而且要与email表中的title字段对应。
范例:测试增加程序(由于版本的问题没有与下一个例子做出区分)
package cn.cgj.test; import cn.cgj.dbc.HibernateSessionFactory; import cn.cgj.pojo.Member; public class MemberTestInsert { @SuppressWarnings("unchecked") public static void main(String[] args) { Member mem = new Member(); mem.setMid("daguo" + System.currentTimeMillis()); mem.setName("大国"); mem.getEmails().add("cgjdreaming@126.com"); mem.getEmails().add("cgjdreaminghq@126.com"); mem.getEmails().add("cgjdreamingxs@126.com"); HibernateSessionFactory.getSession().save(mem); HibernateSessionFactory.getSession().beginTransaction().commit(); HibernateSessionFactory.closeSession(); } } |
Hibernate: insert into mldn.member (name, mid) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) |
等于是现在发现在增加member表数据的同时,email表中的数据也一起被增加了,所以这就实现了一个一对多的操作关系(毕竟表示多的一方表只有一个字段)。
范例:查询数据
package cn.cgj.test; import cn.cgj.dbc.HibernateSessionFactory; import cn.cgj.pojo.Member; public class MemberTestSelectById { public static void main(String[] args) { Member mem = (Member) HibernateSessionFactory.getSession().get(Member.class, "daguo1456840680489"); System.out.println(mem); HibernateSessionFactory.closeSession(); } } |
Hibernate: select member0_.mid as mid0_0_, member0_.name as name0_0_ from mldn.member member0_ where member0_.mid=? Hibernate: select emails0_.mid as mid0_0_, emails0_.title as title0_ from email emails0_ where emails0_.mid=? 大国 [cgjdreaming@126.com, cgjdreamingxs@126.com, cgjdreaminghq@126.com] |
通过以上的操作可以发现,出现了延迟加载的异常,通过执行的SQL语句可以发现时间上现在只查询了Member一张表,而后直接关闭而了session,而随后要想显示出全部的email地址的话,就会发现有一个问题:Session没有了。所以自然无法向email表发出一个查询语句。
范例:取消延迟加载
package cn.cgj.test; import cn.cgj.dbc.HibernateSessionFactory; import cn.cgj.pojo.Member; public class MemberTestSelectById { public static void main(String[] args) { Member mem = (Member) HibernateSessionFactory.getSession().get(Member.class, "daguo1456840680489"); System.out.println(mem); HibernateSessionFactory.closeSession(); } } |
Hibernate: select member0_.mid as mid0_0_, member0_.name as name0_0_ from mldn.member member0_ where member0_.mid=? Hibernate: select emails0_.mid as mid0_0_, emails0_.title as title0_ from email emails0_ where emails0_.mid=? Member [mid=daguo1456840680489, name=大国, emails=[cgjdreaming@126.com, cgjdreamingxs@126.com, cgjdreaminghq@126.com]] |
修改完之后再次执行可以发现,在执行查询Member的同时,由于取消了延时加载(立刻加载),所以所有与Member对应的email数据就全部显示出来了,等于是一次查询执行了两个查询任务。
范例:更新数据
package cn.cgj.test; import cn.cgj.dbc.HibernateSessionFactory; import cn.cgj.pojo.Member; public class MemberTestUpdate { public static void main(String[] args) { Member mem = (Member) HibernateSessionFactory.getSession().get(Member.class, "daguo1456840680489"); mem.getEmails().add("xiaoxiao@126.com"); HibernateSessionFactory.getSession().update(mem); HibernateSessionFactory.getSession().beginTransaction().commit(); HibernateSessionFactory.closeSession(); } } |
Hibernate: select member0_.mid as mid0_0_, member0_.name as name0_0_ from mldn.member member0_ where member0_.mid=? Hibernate: select emails0_.mid as mid0_0_, emails0_.title as title0_ from email emails0_ where emails0_.mid=? Hibernate: insert into (mid, title) values (?, ?) |
由于现在处于持久的状态所以实现了先删除一个指定的,而后在增加一个新的。
范例:如果现在中间变成了游离态
package cn.cgj.test; import java.util.HashSet; import java.util.Set; import cn.cgj.dbc.HibernateSessionFactory; import cn.cgj.pojo.Member; public class MemberTestUpdate { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) { Member mem = (Member) HibernateSessionFactory.getSession().get(Member.class, "daguo1456840680489"); HibernateSessionFactory.closeSession(); //游离态 Set all = new HashSet(); // 新的Set集合 all.addAll(mem.getEmails()); all.add("daguo@126.com"); mem.setEmails(all); // 改变了整个集合 HibernateSessionFactory.getSession().update(mem); // 持久态 HibernateSessionFactory.getSession().beginTransaction().commit(); HibernateSessionFactory.closeSession(); } } |
Hibernate: select member0_.mid as mid0_0_, member0_.name as name0_0_ from mldn.member member0_ where member0_.mid=? Hibernate: select emails0_.mid as mid0_0_, emails0_.title as title0_ from email emails0_ where emails0_.mid=? Hibernate: update mldn.member set name=? where mid=? Hibernate: delete from where mid=? Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) Hibernate: insert into (mid, title) values (?, ?) |
发现如果此时游离态中的数据被重新填充集合的话,那么Hibernate之中会自动先执行一删除全部数据的操作,而后在执行填充新数据的操作,而这种做法也是在实际开发之中最为常见的一种形式。
范例:删除操作
package cn.cgj.test; import org.hibernate.Query; import cn.cgj.dbc.HibernateSessionFactory; public class MemberTestSelectDelete { public static void main(String[] args) { String hql = "DELETE FROM Member As m WHERE mid=?"; Query query= HibernateSessionFactory.getSession().createQuery(hql); query.setString(0, "daguo1456840680489"); System.out.println(query.executeUpdate()); HibernateSessionFactory.getSession().beginTransaction().commit(); HibernateSessionFactory.closeSession(); } } |
Hibernate: delete from mldn.member where mid=? 1 |