导读
Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现。我们知道多表关系有一对一、一对多(多对一)和多对多三种关系。而1对1关系一般合并为一个表处理,所以本文主要讲解1对多和多对多关系的实现。
一、一对多关系
一对多的关系很多,比如人和籍贯就是一对多的关系,下面就用人和籍贯这个实例来展开说明。
1、数据库的实现
对于一对多关系的建立,我们通常是使用外键(foreign key)来表示。外键列添加在一对多的“多”这一方。这里用person表和province表分别表示人和籍贯,所以这个外键就加入province表中,值就是person表的主键值。
2、实体类的实现
对应数据库表,实体类分别用Person类和Province类表示。而在实体类中就没有外键这种概念了。
对于Person类是“多对一”,即很多人属于同一个省份。所以怎么在Person类中表示所属的这一个省份呢?使用类Province即可。
反过来对于Province类是“一对多”,即一个省份有很多人。那么怎么表示很多人呢?即很多Person类,所以我们很快想到使用集合来保存Person类,这里我们使用Set集合。(Set集合值不会重复更符合实际的需求)。
所以,最终的类实现如下:
1 package domain; 2 ?3 public class Person { 4 ????private Long per_id;//省份证 5 ????private String name;//姓名 6 ????private Integer age;//年龄 7 ?????8 ????//关系 9 ????private Province province;//所属省份10 11 ????public Long getPer_id() {12 ????????return per_id;13 ????}14 15 ????public void setPer_id(Long per_id) {16 ????????this.per_id = per_id;17 ????}18 19 ????public String getName() {20 ????????return name;21 ????}22 23 ????public void setName(String name) {24 ????????this.name = name;25 ????}26 27 ????public Integer getAge() {28 ????????return age;29 ????}30 31 ????public void setAge(Integer age) {32 ????????this.age = age;33 ????}34 35 ????public Province getProvince() {36 ????????return province;37 ????}38 39 ????public void setProvince(Province province) {40 ????????this.province = province;41 ????}42 43 ????@Override44 ????public String toString() {45 ????????return "Person [per_id=" + per_id + ", name=" + name + ", age=" + age + ", province=" + province + "]";46 ????}47 }
1 package domain; 2 ?3 import java.util.HashSet; 4 import java.util.Set; 5 ?6 public class Province { 7 ????private Long pro_id;//省代码 8 ????private String name;//省名 9 ????10 ????//关系11 ????private Set<Person> personSet = new HashSet<Person>();//省份的人口集合12 13 ????public Long getPro_id() {14 ????????return pro_id;15 ????}16 17 ????public void setPro_id(Long pro_id) {18 ????????this.pro_id = pro_id;19 ????}20 21 ????public String getName() {22 ????????return name;23 ????}24 25 ????public void setName(String name) {26 ????????this.name = name;27 ????}28 29 ????public Set<Person> getPersonSet() {30 ????????return personSet;31 ????}32 33 ????public void setPersonSet(Set<Person> personSet) {34 ????????this.personSet = personSet;35 ????}36 ????@Override37 ????public String toString() {38 ????????return "Province [pro_id=" + pro_id + ", name=" + name + ", personSet=" + personSet + "]";39 ????}40 }
3、数据库表和实体类的映射关系
配置文件主要是orm元数据(映射关系)和主配置文件的配置。
3.1、orm元数据的配置
orm元数据的配置和之前的配置几乎一致,主要是如何在配置文件中表示外键。具体看下面的配置方法:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC ?3 ????"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 ????"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 ?????6 ????<hibernate-mapping package="domain" > 7 ?8 ????<class name="Person" table="person" > 9 ????????<id name="per_id" ?>10 ????????????<generator class="identity"></generator>11 ????????</id>12 ????????13 ????<property name="name" column="name" ></property>14 ????<property name="age" column="age" ></property>15 ????16 ????<!-- 多对一关系的配置: -->17 ????<many-to-one name="province" column="pro_id" class="Province" ></many-to-one>18 ????19 ????</class>20 </hibernate-mapping>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC ?3 ????"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 ????"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 ?????6 ????<hibernate-mapping package="domain" > 7 ?8 ????<class name="Province" table="province" > 9 ????????<id name="pro_id" ?>10 ????????????<generator class="identity"></generator>11 ????????</id>12 ????????13 ????<property name="name" column="name" ></property>14 ????15 ????<!-- 一对多关系的配置: -->16 ????<set name="personSet">17 ????????<key column="pro_id"></key>18 ????????<one-to-many class="Person"/>19 ????</set>20 ????21 ????</class>22 </hibernate-mapping>
总结:
多对一:
一对多:
3.2、主配置文件的配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 导入约束 --> 3 <!DOCTYPE hibernate-configuration PUBLIC 4 ????"-//Hibernate/Hibernate Configuration DTD 3.0//EN" 5 ????"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 6 <!-- 主配置文件 --> 7 <hibernate-configuration> 8 ????<session-factory> 9 ????????<!-- 10 ????????#hibernate.dialect org.hibernate.dialect.MySQLDialect11 ????????#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect12 ????????#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect13 ????????#hibernate.connection.driver_class com.mysql.jdbc.Driver14 ????????#hibernate.connection.url jdbc:mysql:///test15 ????????#hibernate.connection.username gavin16 ????????#hibernate.connection.password17 ?????????-->18 ?????????<!-- 数据库驱动 -->19 ????????<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>20 ?????????<!-- 数据库url -->21 ????????<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>22 ?????????<!-- 数据库连接用户名 -->23 ????????<property name="hibernate.connection.username">root</property>24 ?????????<!-- 数据库连接密码 -->25 ????????<property name="hibernate.connection.password">password</property>26 ????????<!-- 数据库方言 -->27 ????????<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>28 ????????29 ????????<property name="hibernate.current_session_context_class">thread</property>30 ????????<property name="hibernate.show_sql">true</property>31 ????????<property name="hibernate.format_sql">true</property>32 ????????<property name="hibernate.hbm2ddl.auto">update</property>33 ????????34 ????????<!-- 引入orm元数据-->35 ????????<mapping resource="domain/Person.hbm.xml" />36 ????????<mapping resource="domain/Province.hbm.xml" />37 ????????38 ????</session-factory>39 </hibernate-configuration>
4、Hibernate代码测试
1 package Test; 2 ?3 import org.hibernate.Session; 4 import org.hibernate.Transaction; 5 import org.junit.Test; 6 ?7 import domain.Person; 8 import domain.Province; 9 import utils.HibernateUtils;10 11 public class Demo {12 ????13 ????@Test14 ????public void test(){15 ????????//1、创建对话session16 ????????Session session = HibernateUtils.openSession(); ???????17 ????????//2、开启事务18 ????????Transaction tx = session.beginTransaction();19 ????????20 ????????//3、操作事务:假设张三和李四籍贯北京,现在讲数据持久化到数据库中21 ????????//---------------------------------22 ????????//创建实体对象23 ????????Province pro = new Province();24 ????????pro.setName("北京");25 ????????Person p1 = new Person();26 ????????Person p2 = new Person();27 ????????p1.setName("张三");28 ????????p2.setName("李四");29 ????????30 ????????//建立对象之间的关系31 ????????//一对多:32 ????????pro.getPersonSet().add(p1);33 ????????pro.getPersonSet().add(p2);34 ????????//多对一35 ????????p1.setProvince(pro);36 ????????p2.setProvince(pro);37 ????????38 ????????//将信息持久化到数据库39 ????????session.save(pro);40 ????????session.save(p1);41 ????????session.save(p2);42 ????????43 ????????//----------------------------------44 ????????45 ????????//4、提交事务46 ????????tx.commit();47 ????????//5、关闭资源 48 ????????session.close();49 ????}50 }
测试结果:
5、扩展:cascade属性和reverse属性
1)cascade属性
cascade属性是配置级联操作的一个配置属性,cascade的属性值有:save-update(级联保存)、delete(级联删除)、all(级联保存和删除)。
级联的意思是当你配置了这个属性,那么你操作这个对象时对应的关系对象也会进行相应操作。比如我在上面的Province映射关系中配置了:
那么当我执行session.save(pro)时就不必再执行session.save(p1)和session.save(p2)。
结论:该属性是用来简化书写的,如果要使用,建议不要使用delete和all,因为级联删除存在很大风险,可能会无意中删除很多数据。
2)reverse属性
另一个属性reverse在一对多关系中可以用来优化性能。reverse有两个值:true和false。当选择true是表示放弃维护外键,默认是false。(这个属性在多对多关系中必须使用,因为不能使用两个表来同时维护外键)。
二、多对多关系
1、数据库的实现
多对多的关系是通过转换为两个一对多来实现的。例如学生选课这个关系,一个学生可以选多门课,每个课程又可以对应很多学生,即多对多关系。这样我们就可以在student表和course表之间增加一个关系表choose表(选课表),用来存储学生id和课程id,以此来建立对应关系。这样多对多的关系就变成了两个一对多的关系。
2、实体类的实现
实体类的创建和一对多是一样的道理。
1 package domain; 2 ?3 import java.util.HashSet; 4 import java.util.Set; 5 ?6 public class Student { 7 ????private Long sid;//学号 8 ????private String sname;//姓名 9 ????10 ????private Set<Course> courseSet = new HashSet<Course>();//选课信息11 12 ????public Long getSid() {13 ????????return sid;14 ????}15 16 ????public void setSid(Long sid) {17 ????????this.sid = sid;18 ????}19 20 ????public String getSname() {21 ????????return sname;22 ????}23 24 ????public void setSname(String sname) {25 ????????this.sname = sname;26 ????}27 28 ????public Set<Course> getCourseSet() {29 ????????return courseSet;30 ????}31 32 ????public void setCourseSet(Set<Course> courseSet) {33 ????????this.courseSet = courseSet;34 ????}35 ????36 }
1 package domain; 2 ?3 import java.util.HashSet; 4 import java.util.Set; 5 ?6 public class Course { 7 ????private Long cid;//课程代码 8 ????private String cname;//课程名 9 ????10 ????private Set<Student> studentSet = new HashSet<Student>();//学生信息11 12 ????public Long getCid() {13 ????????return cid;14 ????}15 16 ????public void setCid(Long cid) {17 ????????this.cid = cid;18 ????}19 20 ????public String getCname() {21 ????????return cname;22 ????}23 24 ????public void setCname(String cname) {25 ????????this.cname = cname;26 ????}27 28 ????public Set<Student> getStudentSet() {29 ????????return studentSet;30 ????}31 32 ????public void setStudentSet(Set<Student> studentSet) {33 ????????this.studentSet = studentSet;34 ????}35 36 }
3、数据库表和实体类的映射关系
这里的配置和之前的配置也是几乎不变,关键在于多对多关系的配置。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC ?3 ????"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 ????"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 ?????6 ????<hibernate-mapping package="domain" > 7 ?8 ????<class name="Student" table="student" > 9 ????????<id name="sid" ?>10 ????????????<generator class="identity"></generator>11 ????????</id>12 ????????13 ????<property name="sname" column="sname" ></property>14 ????15 ????<!-- 多对多关系的配置: -->16 ????<set name="courseSet" table="choose" >17 ????????<key column="sid"></key>18 ????????<many-to-many class="Course" column="cid"></many-to-many>19 ????</set>20 ????21 ????</class>22 </hibernate-mapping>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC ?3 ????"-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 ????"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 ?????6 ????<hibernate-mapping package="domain" > 7 ?8 ????<class name="Course" table="course" > 9 ????????<id name="cid" ?>10 ????????????<generator class="identity"></generator>11 ????????</id>12 ????????13 ????<property name="cname" column="cname" ></property>14 ????15 ????<!-- 多对多关系的配置: -->16 ????<set name="studentSet" table="choose" inverse="true">17 ????????<key column="cid"></key>18 ????????<many-to-many class="Student" column="sid"></many-to-many>19 ????</set>20 ????21 ????</class>22 </hibernate-mapping>
变化:
Student.hbm.xml中
Course.hbm.xml中
主配置文件中:
5、测试
package Test;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.Test;import domain.Course;import domain.Student;import utils.HibernateUtils;public class Demo2 { ???@Test ???public void test(){ ???????//1、创建对话session ???????Session session = HibernateUtils.openSession(); ???????????????//2、开启事务 ???????Transaction tx = session.beginTransaction(); ???????????????//3、操作事务:假设有语数外三门课,张三选了语文和数学,李四选了语文和英语,Tom选了数学。将上述信息持久化到数据库 ???????//--------------------------------- ???????//创建实体对象 ???????Course c1 = new Course(); ???????c1.setCname("语文"); ???????Course c2 = new Course(); ???????c2.setCname("数学"); ???????Course c3 = new Course(); ???????c3.setCname("英语"); ???????????????Student s1 = new Student(); ???????s1.setSname("张三"); ???????Student s2 = new Student(); ???????s2.setSname("李四"); ???????Student s3 = new Student(); ???????s3.setSname("Tom"); ???????//建立对象之间的关系 ???????//课程对应学生 ???????c1.getStudentSet().add(s1); ???????c1.getStudentSet().add(s2); ???????c2.getStudentSet().add(s2); ???????c2.getStudentSet().add(s3); ???????c3.getStudentSet().add(s2); ???????????????//学生对应课程 ???????s1.getCourseSet().add(c1); ???????s1.getCourseSet().add(c2); ???????s2.getCourseSet().add(c2); ???????s2.getCourseSet().add(c3); ???????s3.getCourseSet().add(c2); ???????????????//将信息持久化到数据库 ???????session.save(c1); ???????session.save(c2); ???????session.save(c3); ???????session.save(s1); ???????session.save(s2); ???????session.save(s3); ???????//---------------------------------- ???????????????//4、提交事务 ???????tx.commit(); ???????//5、关闭资源 ????????session.close(); ???}}
测试结果:
Hibernate框架进阶(中篇)之多表关系
原文地址:http://www.cnblogs.com/fzz9/p/8043812.html