Java三大框架之——Hibernate关联映射与级联操做

什么是Hibernate中的关联映射?java

  简单来讲Hibernate是ORM映射的持久层框架,全称是(Object Relational Mapping),即对象关系映射。mysql

  它将数据库中的表映射成对应的对象,以对象的形式展示,这样咱们就能够经过映射的对象来对数据库中的数据进行间接的操做。sql

  关联映射是将数据库中的表映射成与之相对应的对象,当你对这个对象进行操做的时候,Hibernate会对数据库中对应的表执行相应的操做,你对该实体的操做实际上就是在间接的操做数据库中与之相对应的表。数据库

  Hibernate正是实现了这种思想,达到了方便开发人员以面向对象的思想来实现对数据库的操做。 session

Hibernate主要实现的映射关系:app

        

 

Hibernate映射的基本结构框架

    hibernate在实现ORM功能的时候主要用到的文件有:映射类(*.Java)、映射文件(*.hbm.xml)和数据库配置文件(*.properties/*.cfg.xml),它们各自的做用以下。dom

        映射类(*.java):它是描述数据库表的结构,表中的字段在类中被描述成属性,未来就能够实现把表中的记录映射成为该类的对象了。ide

        映射文件(*.hbm.xml):它是指定数据库表和映射类之间的关系,包括映射类和数据库表的对应关系、表字段和类属性类型的对应关系以及表字段和类属性名称的对应关系等。fetch

        数据库配置文件(*.properties/*.cfg.xml):它是指定与数据库链接时须要的链接信息,好比链接哪一种数据库、登陆数据库的用户名、登陆密码以及链接字符串等。固然还能够把映射类的地址映射信息放在这里。

 

hibernate中的关联关系有四种:一对1、一对多、多对1、多对多。

 

关联关系中又分为单向关联与双向关联

 

      单向关联:单向关联是指只有一方有另外一方的关联信息而另外一方没有关联信息                    

 

          

 

            A——>B  

 

            A对象中有B对象的关联信息

 

            B对象中没有A对象的关联信息

 

            咱们能够经过A对象中B的关联信息查询或修改B对象的信息但没法经过B对象来查询修改A对象的信息

 

            同理A<——B也是单向关联

 

            这种只是单方面的关联咱们称为单向关联

 

       双向关联:双向关联是指两方都有另外一方的关联信息

 

          

 

            A<——>B

 

            A对象中有B对象的关联信息

 

            B对象中也有A对象的关联信息

 

            咱们能够经过A对象中B的关联信息查询或修改B对象的信息也能够经过B对象来查询修改A对象的信息

 

            这种两方都有另外一方的关联信息咱们称为双向关联

 

单向关联通常在一方配置多方不进行配置

  如:一对多 单向关联在“一”的一方配置文件里进行配置,"多"的一方不进行配置

双向关联两方都要配置

  如:一对多 双向关联在“一”的一方配置文件里须要配置,“多”的一方也须要进行配置

经过下面的代码会慢慢了解

 

下面咱们来详细了解一下一对1、一对多、多对1、多对多的单向和双向关联:

 

 

            一对一关联映射

 

 

  一对一关联:一对一是指一个对象对应一个对象  如:一我的只有一个身份证。

      在两个数据表之间的一对一关系能够有两种实现方法,其中一种就是经过两个表的主键相关联,另外一种是经过外键相关联

        如:一我的(Person)对应一个地址(Address)代码以下。

  一对一主键单向关联: 

        Person——>Address

 

public class Person {
    private int personid;
    private String name;
    private int age;
    //在Person对象中有Address对象的关联信息
    private Address address;
 
public class Address{
    //Address对象中没有Person对象的关联信息
    private int addressid;
    private String addressdetail;

 

 

 

这种单方面有另外一个对象的关联信息的时候咱们称为单向关联,再来看一下两个表中的映射hbm.xml文件:

 

Person.hbm.xml
<hibernate-mapping>
    <class name="com.entity.Person" table="PERSON">
        <id name="personid" column="presonid">
            <!--基于主键关联时,主键生成策略是foreign,代表根据关联类生成主键-->
            <generator class="foreign">
                <!--关联持久化类的属性名-->
                <param name="property">address</param>
            </generator>
        </id>
        <property name="name"/>
        <property name="age"/>
        <!--constrained设定为true,表示的主键必须与Person中对应资料的主键相同。-->
        <one-to-one name="address" constrained="true"/>
    </class>
</hibernate-mapping>
 

单向关联和双向关联的区别主要在于单向只在一方配置而双向两方都要配置

Address.hbm.xml 

由于是单方面关联因此只在Person.hbm.xml中配置了关联信息而Address.hbm.xml中不作任何配置

因此咱们省略Address.hbm.xml

  …………

 

 

知道了一对一的单向关联,咱们再来了解一下一对一的双向关联,双向关联结合上面的知识可能聪明的小伙伴已经想到了。下面咱们来看一下一对一的双向关联

  

一对一主键双向关联:

      Person<——>Address

 

public class Person implements java.io.Serializable { 

  private Long id; 
  private String name; 
  //双向关联中Person对象中有Adderss对象的关联信息  
  private Address address;
 
public class Address implements java.io.Serializable { 
  private Long id; 
  //Adderss对象中也有Person对象的关联信息  
  private Person person; 
  private String detail;

 

 

 

这种两方面都有另外一个对象的关联信息的时候咱们称为双向关联,再来看一下两个表中的映射hbm.xml文件:

 

Person.hbm.xml
<hibernate-mapping> 
  <class name="entity.Person" table="person"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <generator class="identity" /> 
    </id> 
    <property name="name" type="java.lang.String"> 
      <column name="name" length="24" not-null="true"> 
        <comment>姓名</comment> 
      </column> 
    </property> 
    <one-to-one name="address"/> 
  </class> 
</hibernate-mapping>

 

 

 

单向关联和双向关联的区别主要在于单向只在一方配置而双向两方都要配置


Address.hbm.xml
<hibernate-mapping> 
  <class name="entity.Address" table="address" catalog="mydb"> 
    <id name="id" type="java.lang.Long"> 
      <column name="id" /> 
      <!-- class="foreign": 一对一主键映射中,使用另一个相关联的对象的标识符 --> 
      <generator class="foreign"> 
        <param name="property">person</param> 
      </generator> 
    </id> 
    <property name="detail" type="java.lang.String"> 
      <column name="detail" length="120" not-null="true"> 
        <comment>详细地址</comment> 
      </column> 
    </property> 
    <!-- 表示在address表存在一个外键约束,外键参考相关联的表person --> 
    <one-to-one name="person" constrained="true" /> 
  </class> 
</hibernate-mapping>

 当咱们操做Person对象时,能够对Address对象进行操做,也能够操做Address对象时对Person对象进行操做这样就造成了双向的关联

 

 

双向关联还须要在hibernate.cfg.xml中进行配置

<hibernate-configuration> 

  <session-factory> 
    <property name="connection.username">root</property> 
    <property name="connection.url"> 
      jdbc:mysql://localhost:3306/testdb 
    </property> 
    <property name="dialect"> 
      org.hibernate.dialect.MySQLDialect 
    </property> 
    <property name="connection.password">xiaohui</property> 
    <property name="connection.driver_class"> 
      com.mysql.jdbc.Driver 
    </property> 
    <property name="show_sql">true</property> 
    <property name="format_sql">true</property> 

   <!--在hibernate.cfg.xml中配置hbm.xml文件--> <mapping resource="com/entity/Person.hbm.xml" /> <mapping resource="com/entity/Address.hbm.xml" /> </session-factory> </hibernate-configuration>

 

 

咱们再来看一下一对一的外键关联

  一对一外键单向关联:

      Person——>Address

public class Person {
    private int personid;
    private String name;
    private int age;
    private Address address;
 
public class Address{
    private int addressid;
    private String addressdetail;

 

 

 

双向和单向关联你们应该已经了解了 这里就很少作介绍了直接上代码:

Address.hbm.xml
<!--address中不作任何配置因此咱们省略-->

  …………………………
<!--单向关联和双向关联的区别在于单向关联只在一方配置双向关联两方都要配置--> Person.hbm.xml <hibernate-mapping> <class name="com.entity.Person" table="PERSON"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--用来映射关联PO column是Address在该表中的外键列名,增长unique变成惟一的--> <many-to-one name="address" unique="true"/> </class> </hibernate-mapping>

外键关联和主键关联不一样的地方是采用<many-to-one>标签来映射,一对一惟一外键关联映射实际上是多对一的特例。<many-to-one>指定多的一端unique为true,这样就限制了多的一端的多重性为一,就是这样来映射的。

 

 

一对一外键双向关联:

      Person<——>Address

public class Person implements java.io.Serializable { 

  private Long id; 
  private String name; 
  private Address address;
 
public class Address implements java.io.Serializable { 
  private Long id; 
  private Person person; 
  private String detail;

 

Person.hbm.xml <hibernate-mapping> 
  <class name="com.entity.Person" table="person"> 
    <id name="personid" type="java.lang.Long"> 
      <column name="personid" /> 
      <generator class="identity" /> 
    </id> 
    <property name="name" type="java.lang.String"> 
      <column name="name" length="24" not-null="true"> 
        <comment>姓名</comment> 
      </column> 
    </property> 
  <!--双向关联配置--> <one-to-one name="address" /> </class> </hibernate-mapping> Address.hbm.xml <hibernate-mapping> <class name="com.entity.Address" table="address" catalog="testdb"> <id name="addressid" type="java.lang.Long"> <column name="addressid" /> <generator class="identity" /> </id> <property name="detail" type="java.lang.String"> <column name="detail" length="120" not-null="true"> <comment>详细地址</comment> </column> </property> <many-to-one name="person" class="entity.Person" unique="true"> <column name="personid"> <comment>人的ID</comment> </column> </many-to-one> </class> </hibernate-mapping>
单向关联和双向关联的区别主要在于单向只在一方配置而双向两方都要配置因此一对一双向关联比单向关联多了一个在Person.hbm.xml文件中配置<one-to-one name="address" />

 双向关联还须要在hibernate.cfg.xml中进行配置

<hibernate-configuration> 

  <session-factory> 
    <property name="connection.username">root</property> 
    <property name="connection.url"> 
      jdbc:mysql://localhost:3306/testdb 
    </property> 
    <property name="dialect"> 
      org.hibernate.dialect.MySQLDialect 
    </property> 
    <property name="connection.password">xiaohui</property> 
    <property name="connection.driver_class"> 
      com.mysql.jdbc.Driver 
    </property> 
    <property name="show_sql">true</property> 
    <property name="format_sql">true</property> 

   <!--在hibernate.cfg.xml中配置hbm.xml文件-->
    <mapping resource="com/entity/Person.hbm.xml" /> 
    <mapping resource="com/entity/Address.hbm.xml" /> 

  </session-factory> 

</hibernate-configuration>

 注意:由于一对一的主键关联映射扩展性很差,当咱们的须要发生改变想要将其变为一对多的时候变没法操做了,因此咱们遇到一对一关联的时候常常会采用惟一外键关联来解决问题,而不多使用一对一主键关联。

 

         一对多关联映射

   一对多关联:一对可能是指一个对象对应多个对象 一样也分为单向关联和双向关联 如:一个教室能够有多个学生

   一对多单向关联:

      Classes——>Student

public class Classes {  
    private int id;  
    private String name;     
    //Set支持延迟加载由于多个学生因此咱们用Set集合关联  
    private Set students;  
}  
public class Student {  
    private int id;  
    private String name;      
}  

 

单向关联只需在一方配置hbm.xml文件Student不须要配置因此就省略了

Classes对象中使用了set属性,可是只是说明了延迟加载的属性,并无为属性配置对应的对象,属性的对象是要在映射文件中来配置的,须要添加set标签,并在set标签中添加<one-to-many>标签,具体以下代码:

Classes.hbm.xml

<hibernate-mapping>  
    <class name="com.hibernate.Classes" table="t_classes">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
        <set name="students">  
            <key column="classesid"></key>  
            <one-to-many class="com.hibernate.Student"></one-to-many>  
        </set>  
    </class>  
</hibernate-mapping>  

 

由于Classes一方是一方对应的Student是多方 因此咱们要用<set>来关联一方

Student.hbm.xml不作任何改变

  省略………………

 

   一对多双向关联:

       Classes<——>Student

public class Classes {  
    private int id;  
    private String name;     
    //Set支持延迟加载  
    private Set<Student> students;  
}  
public class Student {  
    private int id;  
    private String name; 
    //添加class对象关联信息由于是一方因此咱们用一个对象关联
    private Classes classes;     
}  

 

Classes.hbm.xml

  由于与单向一对多配置同样因此就省略了 能够参考上面单向一对多的代码

Student.hbm.xml

双向咱们须要两方都要配置代码以下:

<hibernate-mapping>  
    <class name="com.hibernate.Student" table="t_student">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
        <!-- 在多的一端Student中添加一行新的Classes列 ,而且列的名称要和Classes.hbm.xml的列明相同-->  
        <many-to-one name="classes" column="classesid"></many-to-one>  
    </class>  
</hibernate-mapping>  

 

 

 由于Student一方是多方对应的Classes是一方 因此咱们要用<many-to-one>来关联一方

 

      多对多关联映射

  多对多关联:多对多关联是指多个对象对应多个对象 如:老师能够有多个学生,学生也能够有多个老师

    多对多单向关联:

      Teacher——>Student

public class Teacher {
    private int id;
    private String name;
    private Set<Student> students = new HashSet<Student>();public class Student {
    private int id;
    private String name;
    private String title;
}

 

Teacher.hbm.xml

 

<hibernate-mapping>  
    <class name="com.hibernate.Teacher" table="t_teacher">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
     <!--生成一张新表存放两个关联对象的ID--> <set name="students" table="Teacher_Sutdent">
       <!--将Teacher表的外键关联 注意不是对象的属性是表中的字段--> <key column="teacher_id"></key>
       <!--将Student表的外键关联 注意不是对象的属性是表中的字段-->
       <many-to-many class="com.hibernate.Student" column="student_id"></many-to-many>
     </set>
   </class>
</hibernate-mapping>

 

 

文件中要使用<many-to-many>标签,而且在标签中添加上对应的列关系,由于你要让两个对象中都要清楚它们之间的映射是如何使用的,而且在生成的关系表中哪一列是对应的本身的外键,因此要在该标签中指明,另外在<set>标签中添加table属性会指明要生成新表,下面的示例中添加了t_user_role,因此会生成新的关联表。 

Student.hbm.xml不作任何配置因此省略

  …………

  多对多双向关联:

      Teacher<——>Student

 

public class Teacher {
    private int id;
    private String name;
    private Set<Student> students = new HashSet<Student>();public class Student {
    private int id;
    private String name;
    private String title;
    private Set<Teacher> teachers = new HashSet<Teacher>();

 

 

 

Teacher.hbm.xml同单向多对多同样故省略

  …………

Student.hbm.xml

<hibernate-mapping>  
    <class name="com.hibernate.Student" table="t_student">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
     <!--生成一张新表存放两个表的Id-->
        <set name="teachers" table="Teacher_Student">  
       <!--将Teacher表的外键关联 注意不是对象的属性是表中的字段-->
            <key column="student_id"></key>  
       <!--将Student表的外键关联 注意不是对象的属性是表中的字段--> 
       <many-to-many class="com.hibernate.Teacher" column="teacher_id"></many-to-many> 
      </set> 
   </class> 
</hibernate-mapping>

 

 

 

        多对一关联

    对比一对一关联映射和多对一惟一外键关联映射,其实它们两个都是使用了<many-to-one>本质上都是外键约束,只不过一对一的是惟一映射,须要添加unique="true"的属性,其它的它们两个是相同的。

  多对一关联:多对一关联是指多个对象对应一个对象 如:多个员工对应一个部门

    多对一单向关联:

public class Department {  
    private int id;  
    private String name;  
}  

public class Employee {  
    private int id;  
    private String name;  
    private Department depart;//注意这里是以部门的对象来做为员工的属性的,这个思想很关键,是创建起部门和员工关联的关键  
      
}  

 

Department.hbm.xml不作任何配置故省略  

  …………    

Employee.hbm.xml

<hibernate-mapping package="com.suo.domain">  
      
    <class name="Employee">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
        <many-to-one name="depart"></many-to-one>  
        <!-- many-to-one指明了外键 ,会根据反射机制,找到要和Employee创建多对一关系的类,该列默认的是能够为空的-->  
    </class>  
      
</hibernate-mapping>  

 

   多对一双向关联:

public class Department {  
    private int id;  
    private String name;
    private Set<Employee> emps;//用集合来存储员工     
}  

public class Employee {  
    private int id;  
    private String name;  
    private Department depart;//注意这里是以部门的对象来做为员工的属性的,这个思想很关键,是创建起部门和员工关联的关键  
      
}  

 

Departement .hbm.xml

<hibernate-mapping package="com.suo.domain">  
      
    <class name="Department">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
          
        <set name="emps">  
            <key column="depart_id"/><!-- key指明了员工表中的外键-->  
            <one-to-many class="Employee"/><!-- one-to-many指明了和哪一个类进行一对多的映射 -->  
        </set>  
        <!--   
            用set标签表示Department中的员工集合的属性,这个属性并无映射到数据库中的部门表中,  
            即部门表中,并无emps这样的一个列。  
         -->  
    </class>  
      
</hibernate-mapping>  

 

Employee.hbm.xml同单向关联配置相同故省略

  …………

 

       级联操做 Cascade:

 一.简单的介绍

cascade和inverse (Employee – Department)

l  Casade用来讲明当对主对象进行某种操做时是否对其关联的从对象也做相似的操做,经常使用的cascade:

         none,all,save-update,delete, lock,refresh,evict,replicate,persist,

         merge,delete-orphan(one-to-many)。

   通常对many-to-one,many-to-many不设置级联,

     在<one-to-one>和<one-to-many>中设置级联。

l  inverse表“是否放弃维护关联关系”(在Java里两个对象产生关联时,对数据库表的影响),在one-to-many和many-to-many的集合定义中使用,inverse=”true”表示该对象不维护关联关系;

   该属性的值通常在使用有序集合时设置成false(注意hibernate的缺省值是false)。

         one-to-many维护关联关系就是更新外键。many-to-many维护关联关系就是在中间表增减记录。

         注: 配置成one-to-one的对象不维护关联关系

 

二,属性的解析
class元素的lazy属性设定为true,表示延迟加载,若是lazy设为false,则表示当即加载。如下对这二点进行说明。
     当即加载:表示Hibernate在从数据库中取得数据组装好一个对象(如学生1)后, 会当即再从数据库取得数据组装此对象所关联的对象(如学生证1)。
     延迟加载:表示Hibernate在从数据库中取得数据组装好一个对象(如学生1)后,不会当即再从数据库中取得数据组装此对象所关联的对象(如学生1),而是等到须要时,才会从数据库取得数据组装此关联对象。

 

<one-to-one>元素的cascade属性代表操做是否从父对象级联到被关联的对象,

它的取得能够是如下几种:


     none:在保存,删除或修改当前对象时,不对其附属对象(关联对象)进行级联操做。它是默认值。
     save-update:在保存,更新当前对象时,级联保存,更新附属对象(临时对象,游离对象)。
     delete:在删除当前对象时,级联删除附属对象。
     all:全部状况下均进行级联操做,即包含save-update和delete操做。
     delete-orphan:删除和当前对象解除关系的附属对象。


<one-to-one>元素的fetch属性的可选值是join和select,默认是select。当fetch属性设定为join时,表示链接抓取(Join fetching):Hibernate经过在Select语句中使用outer join(外链接)来得到对象的关联实例或者关联集合。

  当fetch属性设定为select时,表示查询抓取(Select fetching):须要另外发送一条Select语句抓取当前对象的关联实体或集合。

三。代码练习

<set name="emps" cascade="save-update">
 <key column="depart_id"/>
  <one-to-many class="Employee"/>
</set>

<set name="students" table="taacher_student" inverse="true"><!-- table是用来指定中间表的属性 -->
<key column="teacher_id"></key><!-- 查找教师id时,连接中间表表的teacher_id -->
<many-to-many class="Student" column="student_id"></many-to-many>
</set>

关系映射总结:

 

      单向关联

  一对一主键关联:单向关联时咱们须要在有关联信息一方的配置文件里加入<one-to-one  constrained="true">而且将constrained属性设置为true 表示的主键必须与这个对象中对应资料的主键相同

 

  一对一外键关联:单向关联时咱们须要在有关联信息一方的配置文件里加入<many-to-one unique="true">而且将unique属性设置为true 表示这个主键是惟一的

  一对多单向关联:单向关联时咱们须要在有关联信息一方的配置文件里加入<set>在<set>中加入<one-to-many/>

      <set>  

         <key column="关联的外键">

         <one-to-many/>

      </set>

  多对多单向关联:单向关联时咱们须要在有关联信息一方的配置文件里加入<set>在<set 中生成一张新表用来存放两个表的外键table="">中加入<key column="当前表的外键ID"><many-to-many clasee="关联对象路径" column="关联对象表的Id">

      <set table="">

          <key column=""/>

          <many-to-many class="" column="">

      </set>

  多对一单向关联:单向关联时咱们须要在有关联信息一方的配置文件里加入<many-to-one>

 

       双向关联

  一对一主键关联:在从表的一方加入<one-to-one constrained="true">还须要在主表加入<one-to-one>

    一对一外键关联:除了在从表中加入<many-to-one unique="true">也须要在主表加入<one-to-one>

    一对多双向关联:除了在一方中加入<set><one-to-many></set>还须要在多放加入<many-to-one>

    多对多双向关联:须要在两方都加入<set><many-to-many></set>  注:<set>中的table="表名"   代表两方的配置要同样

 

       <set name="关联对象的属性名" table="生成一张新表">

         <key column="当前对象数据库表的外键"/>

         <many-to-many class="关联对象的类路径" column="关联对象数据库表的外键">

       </set>

   多对一双向关联:要在多方中加入<many-to-one>还要在一方中加入<set>

            <set>

               <key column="关联外键"/>

               <one-to-many>

            </set>

相关文章
相关标签/搜索