web进修之—Hibernate 关系映射(3)

概述

Hibernate的关系映射是Hibernate使用的难点或者是重点(别担心,不考试哦~),按照不同的分类方式可以对这些映射关系做一个分类,如:

按对象对应关系分:

  • 一对一
  • 多对一/一对多
  • 多对多

按对象对应关系的方向分:

  • 单向
  • 双向

按是否使用连接表分(当然了像多对多是必须使用连接表的):

  • 使用连接表
  • 不使用连接表

在使用Hibernate中常常不会分得这么仔细,常常是集中分类方式糅合起来使用,但是这个分类可以帮助我们理解Hibernate中的映射关系。

在进行详细的介绍之前,首先需要明确几个点:

  • Hibernate纷繁复杂的映射关系只是一种面向对象的思维方式,在数据库中就是体现在外键上关联上,所以理解了数据库中的外键关联,再回过头来看映射关系就柳暗花明了;
  • index在数据库中的作用:为了提高查询该列的效率;
  • constrain的作用:对该列的值进行约束(废话。。。),各个取值的含义如下
  • MUL:该列的值可以重复

  • <li><font face="宋体"><font size="3">UNI:该列不能有重复的值</font> </font></li>
    
    <li><font face="宋体"><font size="3">FK:外键,一般定义的时候会有参考哪一个表的哪一个字段</font> </font></li>
    

代码

废话少说,是时候展现真正的代码啦

先看两个类Person,Address(你没看错,这是官方用来举例子的两个类)

  1. public class Address {   
  2.     private long id;   
  3.     private Set<Person> people;   
  4.     private Person person;   
  5.   
  6.     // setter,getter   
  7. }   
  8. public class Person {   
  9.     private long id;   
  10.     private Address address;   
  11.     private Set<Address> addressList;   
  12.   
  13.     // setter,getter   
  14. }  

各种映射关系的配置文件person.hbm.xml,里面包括单向关联的配置(在靠前面),包含双向关联的配置(紧随单向之后)

  1. <!DOCTYPE hibernate-mapping PUBLIC   
  2.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  3.         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
  4.   
  5. <hibernate-mapping package="org.lep.hibernate.model" >  
  6.   
  7.     <class name="Person" table="person">  
  8.         <id name="id" column="person_id">  
  9.             <generator class="increment">  
  10.             </generator>  
  11.         </id>  
  12.         <!--单向关联 start-->  
  13.         <!--多对一是一对多的反向关联,一对多、多对一就构成了多对多-->  
  14.   
  15.         <!--多对一,只需要在many的一方使用many-to-one进行映射即可,和其他id、property一样name表示model里面的属性名称-->  
  16.         <!--<many-to-one name="address" column="address_id" not-null="true" />-->  
  17.   
  18.         <!--一对一,基于外键,把many-to-one的unique设置为true之后就是单向一对一,在数据库中的体现就是这个外键的值是唯一(key=UNI,如果没有设置unique的话key=mul)的,那也就是只能对应一个Address-->  
  19.         <!--有not-null约束的时候注意save对象的顺序,如果没有不用注意顺序hibernate会在保存了关联的对象之后,update到当前对象对应的表-->  
  20.         <!--<many-to-one name="address" column="address_id" not-null="true" unique="true" />-->  
  21.   
  22.   
  23.         <!--一对一,基于主键,将主键作为外键的时候,关联的对象和本对象的save顺序是有关系的,要先savereference的对象,然后在保存本对象-->  
  24.         <!-- constrained说明主键上存在一个约束,即外键,参考address-->  
  25.         <!--<id name="id" column="person_id">-->  
  26.             <!--<generator class="foreign">-->  
  27.                 <!--<param name="property">address</param>-->  
  28.             <!--</generator>-->  
  29.         <!--</id>-->  
  30.         <!--<one-to-one name="address" constrained="true" />-->  
  31.   
  32.         <!--一对多-->  
  33.         <set name="addressList">  
  34.             <key column="person_id" >  
  35.             </key>  
  36.             <one-to-many class="Address"></one-to-many>  
  37.         </set>  
  38.   
  39.         <!--单向关联 end-->  
  40.   
  41.         <!--单向关联——基于连接表 start-->  
  42.         <!--使用多对多和join的时候会产生中间表-->  
  43.         <!--一对多使用many-to-many会产生一张中间表-->  
  44.         <!--<set name="addressList" table="per_addr">-->  
  45.             <!--<key column="person_id"></key>-->  
  46.             <!--<many-to-many column="address_id" class="Address" unique="true" />-->  
  47.         <!--</set>-->  
  48.   
  49.         <!--多对一-->  
  50.         <!--<join table="per_addr" optional="true">-->  
  51.             <!--<key column="peron_id"></key>-->  
  52.             <!--<many-to-one name="address" column="address_id" not-null="true"></many-to-one>-->  
  53.         <!--</join>-->  
  54.   
  55.         <!--一对一-->  
  56.         <!--<join table="per_addr" optional="true">-->  
  57.             <!--<key column="person_id"></key>-->  
  58.             <!--<many-to-one name="address" column="address_id" not-null="true" unique="true" />-->  
  59.         <!--</join>-->  
  60.   
  61.         <!--多对多-->  
  62.         <!--<set name="addressList" table="per_addr">-->  
  63.             <!--<key column="person_id"></key>-->  
  64.             <!--<many-to-many column="address_id" class="Address"></many-to-many>-->  
  65.         <!--</set>-->  
  66.         <!--单向关联——基于连接表 end-->  
  67.   
  68.         <!--双向关联 start-->  
  69.   
  70.         <!--多对一/一对多-->  
  71.         <!--<many-to-one name="address" column="address_id" not-null="true" />-->  
  72.   
  73.         <!--一对一,基于外键关联-->  
  74.         <!--<many-to-one name="address" column="address_id" unique="true" not-null="true" />-->  
  75.   
  76.         <!--一对一,基于主键关联-->  
  77.         <!--<one-to-one name="address" />-->  
  78.   
  79.         <!--双向关联 end-->  
  80.   
  81.         <!--双向关联,使用连接表 start-->  
  82.   
  83.         <!--多对一/一对多-->  
  84.         <!--<set name="addressList" table="per_addr">-->  
  85.             <!--<key column="person_id"></key>-->  
  86.             <!--<many-to-many class="Address" column="address_id" unique="true" />-->  
  87.         <!--</set>-->  
  88.   
  89.         <!--一对一,必须指定column-->  
  90.         <!--<join table="per_addr" optional="true">-->  
  91.             <!--<key column="person_id" unique="true"></key>-->  
  92.             <!--<many-to-one name="address" column="address_id" class="Address" unique="true" />-->  
  93.         <!--</join>-->  
  94.   
  95.         <!--多对多-->  
  96.         <!--<set name="addressList" table="per_addr">-->  
  97.         <!--<key column="person_id"></key>-->  
  98.         <!--<many-to-many column="address_id" class="Address"></many-to-many>-->  
  99.         <!--</set>-->  
  100.   
  101.         <!--双向关联,使用连接表 end-->  
  102.     </class>  
  103. </hibernate-mapping>  

address.hbm.xml(只有双向关联的配置)

  1. <!DOCTYPE hibernate-mapping PUBLIC   
  2.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  3.         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
  4.   
  5. <hibernate-mapping package="org.lep.hibernate.model" >  
  6.     <class name="Address" table="address">  
  7.         <id name="id" column="address_id">  
  8.             <generator class="increment"/>  
  9.         </id>  
  10.   
  11.         <!--双向关联 start-->  
  12.   
  13.         <!--多对一/一对多-->  
  14.         <!--<set name="people" inverse="true">-->  
  15.             <!--<key column="address_id"></key>-->  
  16.             <!--<one-to-many class="Person" />-->  
  17.         <!--</set>-->  
  18.   
  19.         <!--一对一,基于外键关联-->  
  20.         <!--<one-to-one name="person" constrained="true"/>-->  
  21.   
  22.         <!--一对一,基于主键关联-->  
  23.         <!--<id name="id" column="person_id">-->  
  24.             <!--<generator class="foreign">-->  
  25.                 <!--<param name="property">person</param>-->  
  26.             <!--</generator>-->  
  27.         <!--</id>-->  
  28.         <!--<one-to-one name="person" constrained="true"/>-->  
  29.   
  30.         <!--双向关联 end-->  
  31.   
  32.         <!--双向关联,使用连接表 start-->  
  33.   
  34.         <!--多对一/一对多-->  
  35.         <!--<join table="per_addr" inverse="true" optional="true">-->  
  36.             <!--<key column="address_id"></key>-->  
  37.             <!--<many-to-one name="person" column="person_id" not-null="true"></many-to-one>-->  
  38.         <!--</join>-->  
  39.   
  40.         <!--一对一,必须指定column-->  
  41.         <!--<join table="per_addr" inverse="true" optional="true">-->  
  42.             <!--<key column="address_id" unique="true"></key>-->  
  43.             <!--<many-to-one name="person" column="person_id" unique="true"  />-->  
  44.         <!--</join>-->  
  45.   
  46.         <!--多对多-->  
  47.         <!--<set name="people" inverse="true" table="per_addr">-->  
  48.         <!--<key column="address_id"></key>-->  
  49.         <!--<many-to-many column="person_id" class="Person"></many-to-many>-->  
  50.         <!--</set>-->  
  51.   
  52.         <!--双向关联,使用连接表 end-->  
  53.   
  54.     </class>  
  55. </hibernate-mapping>  

试验过这些配置之后,我们可以总结出:

  • 一对一可以通过主键关联,也可以使用外键关联
  • 通过使用unique属性可以将多(many)的关系变为一(one)的关系,比如一对一,可以使用many-to-one unique=”true”
  • 在使用many-to-many或者使用join的时候才会产生连接表(中间表),可以根据实际情况来决定是否采用产生中间表的配置(比如查询的性能,业务逻辑的需要)
  • 如果是双向关系,在一边配置之后,另一边使用inverse=”true”来告诉Hibernate有谁来控制
  • 推荐外键设置not null,这样设置后就要注意保存对象的顺序了,比如person对address单向关联(Person有一个属性Address),那么person表里面就会有一个address_id的外键,如果这个外键设为not null,那么save的时候应该先save address,再save person
  1. Person p = new Person();   
  2. Address addr = new Address();   
  3. p.setAddress(addr);   
  4.   
  5. // 正确   
  6. session.beginTransaction();   
  7. session.save(address);   
  8. session.save(p);   
  9. session.getTransaction().commit();   
  10.   
  11. // 运行会报错,因为外键address设为了not null,在save p的时候,address_id还没有值,所以不满足非空的约束   
  12. session.beginTransaction();   
  13. session.save(p);   
  14. session.save(address);   
  15. session.getTransaction().commit();  

因为外键address设为了not null,在save p的时候,address_id还没有值,所以不满足非空的约束



如果说大家对Hibernate理解比较熟了,只是想看看具体配置文件怎么样写,那么到上面就可以了,如果还想探究一下Hibernate和数据库的对应关系那请继续,先看一个文件(HIbernate在建立上面的映射关系的时候产生的数据库语句)

  1. 单向   
  2. 多对一   
  3. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  4. Hibernate: create table person (person_id bigint not null, address_id bigint not null, primary key (person_id))   
  5. Hibernate: alter table person add index FK_o8tnkglv9n1eeqmo7de7em37n (address_id), add constraint FK_o8tnkglv9n1eeqmo7de7em37n foreign key (address_id) references address (address_id)   
  6.   
  7. 一对一   
  8.     基于外键   
  9. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  10. Hibernate: create table person (person_id bigint not null, address_id bigint not null, primary key (person_id))   
  11. Hibernate: alter table person add constraint UK_o8tnkglv9n1eeqmo7de7em37n unique (address_id)   
  12. Hibernate: alter table person add index FK_o8tnkglv9n1eeqmo7de7em37n (address_id), add constraint FK_o8tnkglv9n1eeqmo7de7em37n foreign key (address_id) references address (address_id)   
  13.   
  14.     基于主键   
  15. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  16. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  17. Hibernate: alter table person add index FK_acrq16tm1ioc620qk2nm5gwyg (person_id), add constraint FK_acrq16tm1ioc620qk2nm5gwyg foreign key (person_id) references address (address_id)   
  18.   
  19. 一对多   
  20. Hibernate: create table address (address_id bigint not null, person_id bigint, primary key (address_id))   
  21. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  22. Hibernate: alter table address add index FK_5k57pkctki2o1wpmk2880r74j (person_id), add constraint FK_5k57pkctki2o1wpmk2880r74j foreign key (person_id) references person (person_id)   
  23.   
  24. 单向——中间表   
  25. 一对多   
  26. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  27. Hibernate: create table per_addr (person_id bigint not null, address_id bigint not null, primary key (person_id, address_id))   
  28. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  29. Hibernate: alter table per_addr add constraint UK_8v3twe5k7nlb8wcjqvcpydab6 unique (address_id)   
  30. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  31. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)   
  32.   
  33. 多对一   
  34. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  35. Hibernate: create table per_addr (peron_id bigint not null, address_id bigint not null, primary key (peron_id))   
  36. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  37. Hibernate: alter table per_addr add index FK_7xqe3kidwvogwcohihqla5ehv (peron_id), add constraint FK_7xqe3kidwvogwcohihqla5ehv foreign key (peron_id) references person (person_id)   
  38. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  39.   
  40. 一对一   
  41. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  42. Hibernate: create table per_addr (person_id bigint not null, address_id bigint not null, primary key (person_id))   
  43. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  44. Hibernate: alter table per_addr add constraint UK_8v3twe5k7nlb8wcjqvcpydab6 unique (address_id)   
  45. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)   
  46. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  47.   
  48. 多对多   
  49. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  50. Hibernate: create table per_addr (person_id bigint not null, address_id bigint not null, primary key (person_id, address_id))   
  51. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  52. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  53. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)   
  54.   
  55.   
  56. 双向   
  57. 多对一/一对多   
  58. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  59. Hibernate: create table person (person_id bigint not null, address_id bigint not null, primary key (person_id))   
  60. Hibernate: alter table person add index FK_o8tnkglv9n1eeqmo7de7em37n (address_id), add constraint FK_o8tnkglv9n1eeqmo7de7em37n foreign key (address_id) references address (address_id)   
  61. 一对一   
  62.     基于外键   
  63. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  64. Hibernate: create table person (person_id bigint not null, address_id bigint not null, primary key (person_id))   
  65. Hibernate: alter table person add constraint UK_o8tnkglv9n1eeqmo7de7em37n unique (address_id)   
  66. Hibernate: alter table address add index FK_scpdoha0q1mmbp5f9lojr3s9x (address_id), add constraint FK_scpdoha0q1mmbp5f9lojr3s9x foreign key (address_id) references person (person_id)   
  67. Hibernate: alter table person add index FK_o8tnkglv9n1eeqmo7de7em37n (address_id), add constraint FK_o8tnkglv9n1eeqmo7de7em37n foreign key (address_id) references address (address_id)   
  68.        
  69.     基于主键   
  70. Hibernate: create table address (person_id bigint not null, primary key (person_id))   
  71. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  72. Hibernate: alter table address add index FK_5k57pkctki2o1wpmk2880r74j (person_id), add constraint FK_5k57pkctki2o1wpmk2880r74j foreign key (person_id) references person (person_id)   
  73.   
  74. 双向——中间表   
  75. 多对一/一对多   
  76. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  77. Hibernate: create table per_addr (address_id bigint not null, person_id bigint not null, primary key (person_id, address_id))   
  78. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  79. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  80. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)   
  81.   
  82. 一对一   
  83. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  84. Hibernate: create table per_addr (person_id bigint not null, address_id bigint, primary key (address_id))   
  85. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  86. Hibernate: alter table per_addr add constraint UK_hdwakolgq6oelbfuallvfbcn4 unique (person_id)   
  87. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)   
  88. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  89.   
  90. 多对多   
  91. Hibernate: create table address (address_id bigint not null, primary key (address_id))   
  92. Hibernate: create table per_addr (person_id bigint not null, address_id bigint not null, primary key (person_id, address_id))   
  93. Hibernate: create table person (person_id bigint not null, primary key (person_id))   
  94. Hibernate: alter table per_addr add index FK_8v3twe5k7nlb8wcjqvcpydab6 (address_id), add constraint FK_8v3twe5k7nlb8wcjqvcpydab6 foreign key (address_id) references address (address_id)   
  95. Hibernate: alter table per_addr add index FK_hdwakolgq6oelbfuallvfbcn4 (person_id), add constraint FK_hdwakolgq6oelbfuallvfbcn4 foreign key (person_id) references person (person_id)  

通过上面的SQL语句,我们可以得出以下几个结论

  • 单向、双向是在对象层面上去考虑的,其实在数据库层面上是一致的,比如单向多对一和双向多对一在表结构上一样的
  • 为了提高效率一般在(中间表)外键上都会创建index

Hibernate中的关系映射是最常用、也是最复杂的。在之前的点滴学习中对Hibernate的映射关系也是一知半解,这次特地花时间认真整理学习了一下,特别是对Hibernate和数据库中表的对应关系进行了认真的探究。

posted @ 2016-03-23 18:56  lacker  阅读(164)  评论(0编辑  收藏  举报