一:關聯關係java
1.關聯關係的方向可分爲單向關聯和雙向關聯sql
單向關聯:假設存在兩張表province表和City表,若是在應用的業務邏輯中,僅須要每一個province實例可以查詢獲得其對應的City實例,而City實例並不須要查詢獲得其對應的province實例;或者反之。數據庫
雙向關聯:既須要每一個province實例可以查詢獲得其對應的City實例,City實例也須要查詢獲得其對應的province實例。session
2.關聯的數量,根據擁有被關聯對象的個數肯定oracle
多對一(many to one):如用戶和組 學生和班級app
一對多(one to many):如用戶和電子郵件工具
多對多(many to many):如學生選課單元測試
一對一(one to one):如用戶和身份證測試
二.單向多對一ui
單向多對一關聯是最多見的單向關聯關係,如:多個城市屬於同一個省份。之因此叫他多對一而不是一對多,是由於他們之間的關係是多的一方來維護的
多個城市屬於一個省份,咱們用多的一方來維護,因此咱們能夠根據城市能夠知道他在哪一個省份,而不須要知道一個省份裏有哪些城市,這就是所謂的單向的。
多對一映射原理:
在多的一端加入一個外鍵(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 }