Pioneer.HengYu

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一:关联关系

1.关联关系的方向可分为单向关联和双向关联

单向关联:假设存在两张表province表和City表,如果在应用的业务逻辑中,仅需要每个province实例能够查询得到其对应的City实例,而City实例并不需要查询得到其对应的province实例;或者反之。

双向关联:既需要每个province实例能够查询得到其对应的City实例,City实例也需要查询得到其对应的province实例。

2.关联的数量,根据拥有被关联对象的个数确定

多对一(many to one):如用户和组 学生和班级

一对多(one to many):如用户和电子邮件

多对多(many to many):如学生选课

一对一(one to one):如用户和身份证

二.单向多对一

     单向多对一关联是最常见的单向关联关系,如:多个城市属于同一个省份。之所以叫他多对一而不是一对多,是因为他们之间的关系是多的一方来维护的

多个城市属于一个省份,我们用多的一方来维护,所以我们可以根据城市可以知道他在哪个省份,而不需要知道一个省份里有哪些城市,这就是所谓的单向的。

多对一映射原理:

在多的一端加入一个外键(FK)指向一的一端,它维护的关系是多指向一

一对多映射原理:

在多的一端加入一个外键(FK)指向一的一端,它维护的关系是一指向多

2.重要属性 - cascade(级联)

级联的意思是指定两个对象之间的操作联动关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作

总共可以取值为:all、none、save-update、delete

all-代表在所有的情况下都执行级联操作

none-在所有情况下都不执行级联操作

save-update-在保存和更新的时候执行级联操作

delete-在删除的时候执行级联操作

三.单向一对多

      所谓单向一对多,就是实体之间的关系由“一” 的一端加载“多” 的一端,关系由“一”的一端来维护,在JavaBean中是在“一”的一端中持有“多”的一端的集合,Hibernate把这种关系反映到数据库的策略是在“多”的一端的表上加一个外键指向“一” 的一端的表的主键(PK)。比如Province(省份)和City(城市)之间是一对多的关系。一个省份里面有很多的城市,站在省份的角度上来看就是一个省份对应多个城市。在一的一端含有一个多的引用的集合(set),我们可以根据省份找到它有哪些城市,而不能根据城市找到他对应的省份

四:双向一对多关联

      所谓双向一对多关联,同时配置单向一对多和单向多对一就成了双向一对多关联,上面两种都是单向的,但是在实际开发过程中,很多时候都是需要双向关联的,它在解决单向一对多维护关系的过程中存在的缺陷起了一定的修补作用

五.注意事项

1.一对多双向关联映:
  在一的一端的集合上使用<key>,在对方表中加入一个外键指向一的一端
  在多一端采用<many-to-one>
2.key标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段错误

3.如果在一的一端维护一对多关联关系,hibernate会发出多余的Update语句,多以我们一般在多的一端维护关联关系
4.关于inverse属性;
 inverse主要用在一对多,多对对双向关联上,inverse可以设置到<set>集合上,
 默认inverse为false,所以我们可以从一的一端和多的一端来维护关联关系,如果inverse为true,我们只能从多的一端来维护关联关系,注意:inverse属性,只影响存储(使存储方向转变),即持久

5.区分inverse和cascade

Inverse:负责控制关系,默认为false,也就是关系的两端都能控制,但这样会造成一些问题,更新的时候会因为两端都控制关系,于是重复更新。一般来说有一端要设为true。
Cascade:负责控制关联对象的级联操作,包括更新、删除等,也就是说对一个对象进行更新、删除时,其它对象也受影响,比如我删除一个对象,那么跟它是多对一关系的对象也全部被删除。
举例说明区别:删除“一”那一端一个对象O的时候,如果“多”的那一端的Inverse设为true,则把“多”的那一端所有与O相关联的对象外键清空;如果“多”的那一端的Cascade设为Delete,则把“多”的那一端所有与O相关联的对象全部删除。

 

持久化类多的一端City.java
 1 持久化类多的一端City.java
 2 
 3 package com.edu.many2one;
 4 /**
 5  *  持久化类
 6  * @author Administrator
 7  *   多的一端
 8  */
 9 public class City {
10 
11     private Integer id;
12     private String name;
13     
14     //关联属性
15     private Province pro;  //必须有
16 
17     public Integer getId() {
18         return id;
19     }
20 
21     public void setId(Integer id) {
22         this.id = id;
23     }
24 
25     public String getName() {
26         return name;
27     }
28 
29     public void setName(String name) {
30         this.name = name;
31     }
32 
33     public Province getPro() {
34         return pro;
35     }
36 
37     public void setPro(Province pro) {
38         this.pro = pro;
39     }
40     
41     
42 }

持久化类一的一端Province.java

 1 持久化类一的一端Province.java
 2 
 3 package com.edu.many2one;
 4 
 5 import java.util.HashSet;
 6 import java.util.Set;
 7 
 8 /**
 9  * 持久化类
10  * @author Administrator
11  *   一的一端
12  */
13 public class Province {
14 
15     private Integer id;
16     private String name;
17     
18     //关联属性
19     private Set<City> cities = new HashSet<City>();  //多的一方放在集合中
20 
21     public Integer getId() {
22         return id;
23     }
24 
25     public void setId(Integer id) {
26         this.id = id;
27     }
28 
29     public String getName() {
30         return name;
31     }
32 
33     public void setName(String name) {
34         this.name = name;
35     }
36 
37     public Set<City> getCities() {
38         return cities;
39     }
40 
41     public void setCities(Set<City> cities) {
42         this.cities = cities;
43     }
44     
45     
46 }

各个实体类配置文件

City.hbm.xml

 1 City配置文件
 2 
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-mapping PUBLIC 
 5     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 7 <hibernate-mapping package="com.edu.many2one">
 8     <class name="City">
 9         <id name="id">
10             <generator class="increment"/>
11         </id>
12         
13         <property name="name"/>
14     
15         <!-- 映射关联属性 -->
16         <!-- pro  和 Province类 多对一 
17             name:  关联属性的名字
18             class: 关联类的类名
19             column: 数据库外键字段的名字
20         
21         -->
22         <many-to-one name="pro" class="Province" column="pid"
23             cascade="save-update"/>
24     </class>
25 
26 </hibernate-mapping>

Province.hbm.xml

 1 Province配置文件
 2 
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-mapping PUBLIC 
 5     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 7 <hibernate-mapping package="com.edu.many2one">
 8     <class name="Province">
 9         <id name="id">
10             <generator class="increment"/>
11         </id>
12         
13         <property name="name"/>
14         
15         <!-- 关联属性 
16             cascade属性:级联操作默认值为none
17                   save-update:级联保存或更新
18                   delete:级联删除
19                   all
20             inverse="true":默认值为false。主控方
21                            true 反转控制权,变为被控方,没有维护关联关系的权利。
22         -->
23         <!-- cities  和City类    一对多 -->
24         <set name="cities" cascade="delete" inverse="true">
25             <key column="pid"/>  <!-- 确定关联的外键列 -->
26             <one-to-many class="City"/>
27         </set>
28     </class>
29     
30 
31 </hibernate-mapping>

 

hibernate.cfg.xml

 1 hibernate配置文件
 2 
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-configuration PUBLIC
 5     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 7 <hibernate-configuration>
 8 <session-factory>
 9     <!-- 配置数据库连接的基本信息 -->
10     <property name="hibernate.connection.driver_class">
11         oracle.jdbc.driver.OracleDriver
12     </property>
13     <property name="hibernate.connection.url">
14         jdbc:oracle:thin:@localhost:1521:XE
15     </property>
16     <property name="hibernate.connection.username">lihengyu</property>
17     <property name="hibernate.connection.password">lihengyu</property>
18 
19     <!-- 数据库的方言 使用的是哪种数据库 -->
20     <property name="hibernate.dialect">
21         org.hibernate.dialect.Oracle10gDialect
22     </property>
23     <!-- 显示sql语句 -->
24     <property name="hibernate.show_sql">true</property>
25     <!-- 自动创建数据库表 
26         none:默认值  有表就使用,没表不创建
27         create:每次都创建新表
28         update: 有表就使用,没表创建。如果持久化类及映射文件发生改变,则发生alter语句修改表结构。
29     -->
30     <property name="hibernate.hbm2ddl.auto">update</property>
31 
32     <!-- 添加映射文件 -->
33     <mapping resource="com/edu/many2one/City.hbm.xml" />
34     <mapping resource="com/edu/many2one/Province.hbm.xml" />
35 
36 </session-factory>
37 
38 
39 </hibernate-configuration>

代码测试

  1 TestHibernate 测试
  2 
  3 package com.edu.many2one;
  4 
  5 import org.hibernate.SessionFactory;
  6 import org.hibernate.Transaction;
  7 import org.hibernate.cfg.Configuration;
  8 import org.hibernate.classic.Session;
  9 import org.junit.Test;
 10 
 11 /**
 12  * 使用单元测试工具,测试hibernate 的增删改查(CRUD)操作
 13  * 
 14  * @author Administrator
 15  * 
 16  */
 17 public class TestHibernate {
 18 
 19     private static SessionFactory sf;
 20     static {
 21         // 1. 加载配置文件
 22         Configuration cfg = new Configuration();
 23         cfg.configure("com/edu/many2one/hibernate.cfg.xml");
 24 
 25         // 2. 获得SessionFactory
 26         sf = cfg.buildSessionFactory();
 27     }
 28     
 29 
 30     /**
 31      *  保存用户
 32      *  1.  保存Province 不保存City
 33      *  2.  保存City  不保存Province
 34      *  3.  先保存Province,再保存City
 35      *  4.  先保存City,再保存Province
 36      */
 37     @Test
 38     public void save() {
 39         
 40         
 41         Session session = sf.openSession();
 42         Transaction tran = session.beginTransaction();
 43         
 44         Province p = new Province();
 45         p.setName("吉林省");
 46         
 47         City c = new City();
 48         c.setName("长春市");
 49         
 50         //维护关联关系
 51         c.setPro(p);
 52         p.getCities().add(c);
 53         
 54         //保存对象
 55         /*
 56          * 1.保存Province 不保存City  city对象是临时状态,不能操作数据库
 57          * TransientObjectException:      临时对象异常
 58         session.save(p);
 59          */
 60         
 61         /*
 62          * 2.  保存City  不保存Province
 63          * TransientObjectException:      临时对象异常
 64          */
 65         session.save(c);
 66         
 67         /*
 68          * 3.  先保存Province,再保存City
 69          * 
 70          *  发送几条sql语句
 71          *  insert into Province (name, id) values (?, ?)
 72             insert into City (name, pid, id) values (?, ?, ?)
 73             update City set pid=? where id=?
 74         session.save(p);
 75         session.save(c);
 76          */
 77         /*
 78          * 4.  先保存City,再保存Province
 79          * 
 80          *  发送4条sql语句
 81          *  insert into City (name, pid, id) values (?, ?, ?)
 82             insert into Province (name, id) values (?, ?)
 83             update City set name=?, pid=? where id=?
 84             update City set pid=? where id=?
 85         session.save(c);
 86         session.save(p);
 87          */
 88         
 89         tran.commit();
 90         session.close();
 91     }
 92     /**
 93      * 查询
 94      * 1.  1号城市属于哪个省份
 95      * 2.  1号省份关联的所有城市
 96      */
 97     @Test
 98     public void find() {
 99         
100         
101         Session session = sf.openSession();
102         Transaction tran = session.beginTransaction();
103         
104         //1
105         //City c = (City) session.get(City.class, 1);
106         //System.out.println(c.getPro().getName());
107         
108         //2
109         Province p = (Province) session.get(Province.class, 1);
110         
111         for(City city:p.getCities()) {
112             System.out.println(city.getName());
113         }
114         tran.commit();
115         session.close();
116     }
117     
118     /**
119      * 删除
120      * 1.  删除5号城市信息
121      * 2.  删除4号省份信息
122      */
123     @Test
124     public void delete() {
125         
126         
127         Session session = sf.openSession();
128         Transaction tran = session.beginTransaction();
129         
130 //        City c = (City) session.get(City.class, 5);
131 //        session.delete(c);
132         
133         Province p = (Province) session.get(Province.class, 4);
134         session.delete(p);
135         
136         tran.commit();
137         session.close();
138     }
139     
140     /*
141      *   City变更
142      *   
143      *   把4号城市变更为2号省份
144      *   
145      */
146     @Test
147     public void update() {
148         
149         
150         Session session = sf.openSession();
151         Transaction tran = session.beginTransaction();
152         
153         //查询信息
154         City c4 = (City) session.get(City.class, 4);
155         Province p2 = (Province) session.get(Province.class, 2);
156         
157         /*
158          * 变更关联关系
159          * 
160          * 此时发送2条update语句。重复操作。 
161          * 关联两端同时维护关系,对象的状态都发生了改变,所有会生成2条update语句
162          * update City set name=?, pid=? where id=?
163            update City set pid=? where id=?
164            
165          *  只要执行一条update就可以更新数据库中的记录
166          *  只需要一端维护关系。
167          *  哪一端维护关联关系?
168          *  领导1  
169          *  全国人民N   主控方
170          *  
171          *  在一对多关联中,需要多的一端作为主控方,来维护关联关系
172          *  那么一的一端就应该交出控制权,作为被控方。
173          */
174         c4.setPro(p2);
175         /*
176          * 虽然,此条删除语句不会影响到数据库中的记录。
177          * 但为了维护程序的健壮性,建议添加此条语句。
178          */
179         p2.getCities().add(c4);
180         
181         //更新  不需要调用update方法
182 //        session.update(c4);
183 //        session.update(p2);
184         
185         
186         tran.commit();
187         session.close();
188     }
189 }

 

posted on 2017-04-07 01:04  Pioneer.HengYu  阅读(187)  评论(0编辑  收藏  举报