zoukankan      html  css  js  c++  java
  • Hibernate框架进阶(中篇)之多表关系

    导读

    Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现。我们知道多表关系有一对一、一对多(多对一)多对三种关系。而1对1关系一般合并为一个表处理,所以本文主要讲解1对多和多对多关系的实现。

    一、一对多关系

    一对多的关系很多,比如人和籍贯就是一对多的关系,下面就用人和籍贯这个实例来展开说明。

    1、数据库的实现

     对于一对多关系的建立,我们通常是使用外键(foreign key)来表示。外键列添加在一对多的“多”这一方。这里用person表和province表分别表示人和籍贯,所以外键就加入person表中,值就是province表的主键值。

    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     @Override
    44     public String toString() {
    45         return "Person [per_id=" + per_id + ", name=" + name + ", age=" + age + ", province=" + province + "]";
    46     }
    47 }
    Person
     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     @Override
    37     public String toString() {
    38         return "Province [pro_id=" + pro_id + ", name=" + name + ", personSet=" + personSet + "]";
    39     }
    40 }
    Province

    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>
    Person.hbm.xml
     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>
    Province.hbm.xml

    总结:

    多对一:

    一对多:

    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.MySQLDialect
    11         #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
    12         #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
    13         #hibernate.connection.driver_class com.mysql.jdbc.Driver
    14         #hibernate.connection.url jdbc:mysql:///test
    15         #hibernate.connection.username gavin
    16         #hibernate.connection.password
    17          -->
    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>
    hibernate.cfg.xml

    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     @Test
    14     public void test(){
    15         //1、创建对话session
    16         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 }
    Student
     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 }
    Course

    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>
    Student.hbm.xml
     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>
    Course.hbm.xml

    变化:

    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();
        }
    }

    测试结果:

  • 相关阅读:
    ios js交互
    再次记录 cocoapods
    CABasicAnimation
    mysql授权
    很简单的代码,但是无法解释的错误
    4款开源免费的数据可视化JavaScript库
    【工具】获取窗口与控件信息
    从网易搬家来的49篇日志
    Git Extensions system.invalidoperationexception尚未提供文件名,因此无法启动进程
    哆啦A梦欺骗了你!浏览器CSS3测试遭质疑
  • 原文地址:https://www.cnblogs.com/fzz9/p/8043812.html
Copyright © 2011-2022 走看看