Hibernate【关联映射】

 

 Hibernate可以以面向对象的方式进行数据库访问,既然是面向对象,我们知道在客观世界中,对象不会孤立的存在,在Hibernate中,Hibernate把这种对象与对象之间的联系称为关联关系,如果在我们设计实体类的时候,可以良好的映射这些关联关系,便可以大大简化持久层数据的访问

  关联关系分为两类:

    单向关系:假如学生,老师这个例子,单向关系就是指只能从老师可以访问学生,或者只能从学生访问老师

     双向关系:还是上面的例子,双向关系是指 能从老师访问学生,能从学生访问老师

 

 单向关系中具体的还有:                   双向关系中具体的有:

    1 -> 1               1 <-> 1

    1 -> N                1 <-> N

    N -> N              N <-> N

    N -> 1

 

  


 

 

(一) 【单向】1 -> N关联

 

  在单向1 -> N关联中,一的持久化类中需要一个集合属性来关联到N的一方,表示有多个N。

  持久化类结构如下:

public class Person implements Serializable{
    private Integer id; //标识符属性
    private String name; //一般属性
    private Set<Address> addresses; //关联对象
       .....
}

---1 -> N(从一个人身上可以知道了他多个住址,而只找到住址,住址不会告诉你这是谁住的)----

public class Address implements Serializable {
    private Integer id;
    private String place;
        ...
}

 

  • 无连接表的关联(外键表示关联关系)

  配置关联关系的两种方式:

    方式一: 使用映射文件(重点)

      (1)*.hbm.xml中核心配置

    <!-- set元素针对的就是持久化类中的Set属性 cascade操作的是一般属性 inverse针对的是外键操作-->
    <set name="addresses" cascade="save-update"  >
            <!-- 外键字段名,告诉Hibernate,personId就是外键,用这个外键建立与Address持久化类的关联 -->
            <key column="personId"></key>
       <!-- 告诉Hibernate,Person持久化类中的set集合,放的是哪个元素 -->
            <one-to-many class="domain.Address" />
      </set>

 

      (2)创建了外键来维护关联关系  

    从数据库查看Address表的结构:

    

 

   方式二:使用注解

     略

 

  • 有连接表的关联(第三方表维护关联关系)

  配置关联关系的方式:

   方式一。使用*.hbm.xml(重点)

    (1)*.hbm.xml中核心配置

        <set name="addresses" cascade="save-update" table="person_address" >
            <!-- 外键表主键为这两个外键id列的组合 -->
            <key column="personId"></key>
            <!-- unique的目的为防止多对一的出现,确保是单向的一对多 -->
            <many-to-many class="domain.Address" column="adresssId" unique="true" />
        </set>

   (2)创建了第三方表的方式维护关联关系  

      在数据库查看第三方表person_address:

      

 

   方式二。使用注解

     略

 

  

  【ps: session.flush()时,进行了哪些操作】

   1。Hibernate会在一级缓存中检查所有持久化状态对象,决定发出update语句或者insert语句

   2。检查所有的持久化对象的关联对象,如果关联对象是由临时状态转换过来的,发出insert语句,如果是从脱管对象转换过来的,判断副本,再决定发不发出update语句

 

  1 -> N 操作

    从1的一端维护时,不需要解除关系,可以直接建立关系。

    从1的一端维护关系的时候,总会发出维护关系的update语句。该update语句就是更新外键,所以1的一方维护效率并不高


 

(二) 【单向】N -> 1关联

  

  概述:常见的多对一关系,是父子关系。父类不能访问子类,而其子类们都可以访问父类。

  下面用到的例子:是人和住址的关系,不论你问小区里的那个居民,都可以得到小区所在的具体地址。但通过具体地址你却不能知道小区有哪些人

 

  • 无连接表的 N -> 1关联

  配置关联关系的两种方式:

   方式一:使用映射文件

<class name="domain.Person" table="PERSON">
     <id name="id"> <column name="ID"></column> 
        <generator class="increment"></generator>
     </id>
     <property name="name">
         <column name="NAME"></column>
     </property> 
    <many-to-one name="address" column="ADDRESS_ID" class="domain.Address" cascade="save-update"></many-to-one> //外键在PERSON中
</class>        

  方式二:使用注解

    略

 

  • 有连接表的N -> 1关联

  配置关联关系的两种方式:

  方式一。使用映射文件配置

      <join table="person_address">
              <key column="pID"></key>
              <many-to-one name="address" class="domain.Address" column="aID"></many-to-one>
          </join>

 

  方式二。使用注解

    略

 

 


 

(三) 【双向】1 <-> N关联

 

  • 无连接表的关联

  配置关联关系的两种方式:

    方式一。使用*.hbm.xml(重点)

      (1.1)对于1的一端*.hbm.xml采用的配置文件

        <!-- 一对多,使用集合 -->
        <set name="addresses" cascade="save-update">
            <key column="personId"></key>
            <one-to-many class="domain.Address"/>
        </set>

     (1.2)对于N的一端*.hbm.xml采用的配置文件

     
<many-to-one name="person" class="domain.Person" column="personId" cascade="save-update"></many-to-one>

     (2) 查看两张表的数据库中的结构

  

  

    方式二。适用注解

 

  • 有连接表的关联

  配置关联关系的方式:

   方式一。使用*.hbm.xml(重点)

    (1.1)对于1的一端*.hbm.xml采用的配置文件

        <set name="addresses" cascade="save-update" table="person_address">
            <key column="personId"></key>
            <many-to-many class="domain.Address" column="addressId"/>
        </set>

 

    (1.2)对于N的一端*.hbm.xml采用的配置文件

        <!-- join元素强制使用连接表 -->
        <join table="person_address">
            <key column="addressId"></key>
            <many-to-one name="person" class="domain.Person" column="personId" cascade="save-update"></many-to-one>
        </join>

 

    (2) 查看两张表的数据库中的结构

  

    方式二。使用注解

 

  总结:

    用1的一方维护关系,1的一方始终会发出维护关系的sql语句,

    如果用多的一方维护关系,他操作的就是N的本身。没有维护关系之说。

    所以多的一方维护效率比较高

  


 

 

(四) 【单向】N -> N关联

  

  • 无连接表的关联

    N -> N 没有外键关联方式。

 

  • 有连接表的关联

  配置关联关系的方式:

  方式一:使用*.hbm.xml(重点)

        <set name="stations"  cascade="save-update" table="BUS_STATION">
            <key column="bId"></key>
            <many-to-many class="domain.Station" column="sID"></many-to-many>
        </set>

 

  方式二:使用注解

     略

 


 

(五) 【双向】N -> N关联

 

  • 无连接表的关联

    N -> N 没有外键关联方式

 

  • 有连接表的关联

  配置关联关系的两种方式:

    方式一。使用*.hbm.xml(重点)

      (1)在N的两端配置

        <set name="stations"  cascade="save-update" table="BUS_STATION">
            <key column="bId"></key>
            <many-to-many class="domain.Station" column="sId"></many-to-many>
        </set>




        <set name="bus"  cascade="save-update" table="BUS_STATION">
            <key column="sId"></key>
            <many-to-many class="domain.Bus" column="bId"></many-to-many>
        </set>

    (2)查看数据库中的结构:ps:如果在<many-to-many>没有指定column的话,会在第三方表中生一个elt的列

      

  

      方式二:使用注解

       略

 


 

(六) 【单向】1 -> 1关联

 

  • 无连接表的关联-主键关联

    方式一:使用映射文件配置

    例子:Station -> Bus。Station的主键与Bus的主键关联

    Bus映射文件不做任何改变,只需改变Station的映射文件

    <class name="domain.Station" table="STATION">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="foreign">
                <param name="property">bus</param>  //该值就是Station持久化类中的属性值,也就是<one-to-one>中的值
            </generator>
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
       <one-to-one name="bus" class="domain.Bus" constrained="true" cascade="save-update"></one-to-one>
    </class>

    其中<one-to-one>中,constrained属性只能在<o-t-o>的映射中使用,如果constrained为true,则表明存在外键与关联表对应,并且关联表中肯定存在对应的的键于其对应,另外该选项最关键的是影响save和delete的先后顺序,例如在save的时候,如果constrained为true,则会先增加关联表,然后增加本表。delete的时候反之

    <one-to-one>的单向关联中,如果constrained为false,则会在查询的时候全部取出用left outer join的方式。如果constrained=true,hibernate即会延迟加载sql,只把主表的查出来,等有用到关联表的再发sql取。

one-to- one的双向关联中,必须设置constrained=true,要不然会有重复数据读,如2个表user,car;在位false时sql如 下:select * from user a left outer join car b on a.id=b.id left outer join on user c on a.id=c.id where a.id=? 删除的时候最好删除从表,删除主表会先查询下主表,在联合查询下

    方式二:使用注解

      略

 

  • 无连接表的关联-外键关联

    方式一:使用映射文件      

     <many-to-one name="bus" class="domain.Bus" cascade="save-update" unique="true" column="bID"></many-to-one>

 

    方式二:使用注解

      略

 

  • 有连接表的关联

    方式一:使用映射文件

      <join table="bus_station">
              <key column="sID"></key>
              <many-to-one name="bus" class="domain.Bus" column="bID" cascade="save-update" unique="true"></many-to-one>
        </join>

 

    方式二:使用注解

       略

 

 


 

 

(七)【双向】1 <-> 1

  •  主键关联

    方式一:使用映射文件

    

   bus.hbm.xml 
<one-to-one name="station" class="domain.Station" cascade="save-update"></one-to-one> station.hbm.xml
  <one-to-one name="bus" class="domain.Bus" cascade="save-update"></one-to-one>

 

    方式二:适用注解

       略

 

  •  无连接表关联

    方式一:使用映射文件

  一开始我试了两个<many-to-one>的方式,试图在两张表都创建外键,但实际结果是建表虽然成功,但只能从一端维护,查阅网上给出的解决方案就是主键关联与外键关联结合的方式,就是如下所示 

    <many-to-one name="bus" class="domain.Bus" cascade="save-update" column="bID" unique="true"></many-to-one>
  <one-to-one name="station" class="domain.Station" property-ref="bus"></one-to-one>

 

    方式二:使用注解

      略

 

  •    有连接表关联

    看了上面的例子不难写出,故不再复述

posted @ 2016-01-12 02:04  a617475430  阅读(294)  评论(0编辑  收藏  举报