級聯(Cascade) : 二個以上的設備經過某種方式鏈接起來,能起到擴容的效果就是級聯。Hibernate級聯(Cascade)是用來講明數據庫中兩個表之間相互關係(一對一,一對多,多對多)中,當對主對象進行某種操做時,是否對其關聯的從對象也做相似的操做(好比有對象Department和Employee,它們之間是一對多的關係,當保存Department時,其對應的Employee是否也相應的保存),常見的級聯(Cascade)有: mysql
(1)none:在保存,刪除或修改當前對象時,不對其附屬對象(關聯對象)進行級聯操做。它是默認值。
(2)save-update:在保存,更新當前對象時,級聯保存,更新附屬對象(臨時對象,遊離對象)。
(3)delete:在刪除當前對象時,級聯刪除附屬對象。
(4)all:全部狀況下均進行級聯操做,即包含save-update和delete等等操做。
(5)delete-orphan:刪除此對象的同時刪除與當前對象解除關係的孤兒對象(僅僅使用於一對多關聯關係中)。 sql
對Hibernate session的每個基本操做,如:persist(),merge(),saveOrUpdate(),delete(),lock(),refresh(),evict(),replicate(),都有一個相關的級聯形式與之對應,他們分別命名爲:create,merge,save-update,delete,lock,refresh,evict,replicate.若是你想對某種關聯操做設置級聯,你只要在映射文件中配置便可,如: 數據庫
若是想同時給級聯設置多個值,能夠如此設置: session
建議: app
1. 通常對<many-to-one>或<many-to-many>關聯關係不設置級聯(Cascade)操做,級聯(Cascade)操做經常被用於<one-to-one>和<one-to-many>. dom
2. 若是子對象的生命週期與父對象的生命週期是聯繫在一塊兒的(一致的),能夠經過設置級聯cascade="all,delete-orphan"來指定它的對象生命週期。 ide
cascade測試程序以下: 性能
1。實體類: 測試
Department以下: this
Employee以下:
映射文件以下:
Department.hbm.xml映射文件以下:
Employee.hbm.xml映射文件以下:
測試程序以下:
由於在映射文件Department.hbm.xml文件中給集合映射set配置了級聯(cascade="save-update"),因此將測試程序中註釋爲1,2的兩句程序(保存set集合中Employee元素的程序)註釋掉,程序也同樣能將這兩個Employee元素保存進數據庫中,測試結果以下所示:
控制檯打印信息以下:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
數據庫表中記錄以下:
mysql> select * from department;
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+
| id | name | depart_id |
+----+-----------------+-----------+
| 1 | employee1 name1 | 1 |
| 2 | employee2 name2 | 1 |
+----+-----------------+-----------+
2 rows in set (0.00 sec)
若是Department映射文件中的set集合映射沒有設置級聯,一樣的程序進行測試,則會拋出以下異常,控制檯打印信息以下:
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set depart_id=? where id=?
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.reiyen.hibernate.domain.Employee
當把Department實例持久化進數據庫後,更新它相關聯的Employee對象時拋出異常,由於此時關聯的Employee是瞬時對象,而不是一個持久化對象。
inverse: 表示「是否放棄維護關聯關係」(在Java裏兩個對象產生關聯時,對數據庫中表的影響),hibernate的缺省值爲false。在<one-to-many>和<many-to-many>關聯關係的集合定義中使用,inverse="true"表示該對象不維護關聯關係。該屬性的值在使用有序集合時(list,array等)時通常設置爲false.<one-to-many>維護關聯關係就是更新外鍵;<many-to-many>維護關聯關係就是在中間表中增減記錄!
cascade 和inverse有什麼區別? 能夠這樣理解,cascade 定義的是關係兩端對象到對象的級聯關係;而inverse定義的是關係和對象的級聯關係。
inverse測試程序以下:
測試類以下:
先在Department.hbm.xml文件中不設置inverse進行測試:
1。測試結果以下,控制檯打印了四條update語句(這是由於關聯對象雙方都要去維護這種關聯關係所致使的結果):
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
2。若是將測試程序中的標記爲1,2的語句註釋掉,或將標記爲3的語句註釋掉再進行測試,控制檯打印的結果就會少兩條update語句,以下所示(此時程序的功能與1一致,數據庫中記錄也同樣,只是此時在對象模型上不是完整的而已,由於在對象模型上,只是告訴了一方與另外一方的關係,而反過爲,另外一方則不知他對應的對象了。其實這對程序沒有任何影響):
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
3。 或者將標記爲5的語句註釋掉,同時將標記爲4的語句的註釋去掉,再運行;結果與2。的同樣只打印兩條update語句。但這兩條update語句與2中的不一樣,由於這兩條語句是因爲
而產生的。此時爲何只有這兩條update語句了呢?由於先保存了Department對象,因此再保存Employee時,直接就能夠將Department對象的值取到,直接保存在數據庫中了,而再也不須要update.因此就少了如下的兩條SQL語句:
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
.產生的SQL語句以下所示:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
4。在cascade程序的基礎上進行修改。將Department.hbm.xml文件進行修改,將cascade="save-update,delete"替換成inverse="true"便可,其他的地方保持原樣。再繼續運行測試程序,這是控制檯打印的信息與測試2的結果一致,也只有兩打update語句,但此時在對象模型上也是完整的,由於對象模型知道了相互對應的另外一方,此時Department對象已經放棄關聯關係的維護了,只有Employee對象去維護他們之間的關聯關係,因此只產生了兩條update語句。inverse"是否放棄維護關聯關係"通常在one的一方設置(其實hibernate不容許多的一端放棄維護關聯關係,而由one的一端維護,由於這是很是低效率的),這比比如一個Teacher與Student這種現實生活中的關係,你讓老師記住每一個學生的名字這是比較困難的一件事情,因此你就讓老師不用去記學生,而讓學生去記老師就好了,這會簡單的多,而只要每一個學生記住了老師,這樣他們的關聯也就能夠維持了。同時,這樣還能夠提升效率。在上例中,當設置了級聯關係後,若是先保存Department,再保存Employee(也就是再執行上例中第三種操做),控制檯就不會再產生update語句了。以下所示:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
但此時有一點須要很是注意:由於你已經設置了讓Department對象放棄維護關聯關係了,因此此時,測試程序中標記爲1,2的語句必定不能少,不然在數據庫中就體現不了它們之間的關聯關係了。註釋掉標記爲1,2的兩句程序,從新運行,結果以下所示,控制檯打印信息以下:
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
沒有了更新外鍵的update語句了。同時查看數據庫表中記錄,employee表中depart_id的值爲null了,以下所示:
mysql> select * from department;
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | department name |
+----+-----------------+
1 row in set (0.00 sec)
mysql> select * from employee;
+----+-----------------+-----------+
| id | name | depart_id |
+----+-----------------+-----------+
| 1 | employee1 name1 | NULL |
| 2 | employee2 name2 | NULL |
+----+-----------------+-----------+
2 rows in set (0.00 sec)
但能夠將測試程序中標記爲3的語句(也即創建Department與Employee之間關係的語句)註釋掉,再從新運行,結果不會有什麼影響,由於如今Department已再也不維護關聯關係了,因此這句程序要與不要沒有區別。
5。若是將上面程序中的set集合映射改爲list集合映射來進行(set集合改爲list集合映射的細節請參看我寫的hibernate集合類(Collections)映射 ,除了修改映射文件外,還得修改測試程序),在list集合映射中設置級聯,以下所示:
再運行如上的測試程序,則會出現以下的異常:
org.hibernate.HibernateException: null index column for collection: com.reiyen.hibernate.domain.Department.emps
由於在list集合映射中須要維護加入list集合中的元素的順序,而inverse=「true」是放棄維護關聯關係。當對象之間的關聯關係都不維護,再談添加入的順序,已沒有什麼意義。因此及在使用hibernate的有序集合時,通常將inverse設置成false.