在資料庫裡,進行增加、修改、刪除記錄的時候,經常會涉及到父子關係的表。
例如:有省份表和城市表,其中城市表有一個外鍵province_id引用到省份表的主鍵。這樣,可以把省份表看成是父表,把城市表看成是子表,城市表記錄的存在依賴於省份表的記錄。(文中提到的例子,所有的代碼在附件裡都有,所以這裡的描述從簡)
一、在MySQL裡的cascade
以下直接在MySQL的控制台操作省份表和城市表
在省份表增加一條“廣東”的記錄,在城市表增加一條“廣州”的記錄,並且把“廣州”的外鍵引用到“廣東”的主鍵。“廣州”的存在依賴於“廣東”,如果刪除省份表的“廣東”,將會影響到城市表的“廣州”。根據城市表的外鍵約束的on delete設定,有如下三種情況:
1、外鍵沒有on delete的設定:當刪除“廣東”的時候,MySQL會報錯,刪除失敗。
2、外鍵設定為on delete cascade:當刪除“廣東”的時候,同時把“廣州”也刪除。
3、外鍵設定為on delete set null:當刪除“廣東”的時候,“廣州”的外鍵province_id會被自動化佈建為null,即“廣州”脫離了對“廣東”的依賴關係。
二、在Hibernate裡的cascade
以下用Hibernate來操作省份表和城市表
首先,在hibernate.cfg.xml檔案配置好串連MySQL資料庫的相關屬性(請在那裡修改登陸資料庫的密碼)。然後,為省份表和城市表添加相關的POJO類和XML對應檔。用SQL語句建表(在附件的test_cascade.sql裡),城市表有一個外鍵province_id引用到省份表的主鍵,並把這個外鍵設定為on delete cascade。這個外鍵約束,在Hibernate變成了雙向的映射關係:City類有一個類型為Province的province屬性,關聯到省份表,在對應檔中是many-to-one的關係;Province類有一個Set<City>的cities屬性,關聯到城市表,在對應檔中是one-to-many的關係。
在Hibernate的對應檔裡,同樣可以設定cascade屬性來控制父子關係。通常在父表設定cascade屬性,有以下幾種情況:
1、沒有設定cascade屬性
用方法addInNoCascade()增加記錄“廣東”和“廣州”(方法在類CityManager裡,以下同),再用方法delete()刪除“廣東”,將會出現異常,系統會說因為“廣東”被城市表外部索引鍵關聯了而不能刪除。用SQL建表時,已經把外鍵設為on delete cascade,怎麼不能把“廣東”刪除的同時,串聯刪除“廣州”呢?用MyEclipse查看城市表,發現有兩個外鍵,:
第2個外鍵是用SQL建表時產生的,設定了on delete cascade;而第1個外鍵應該是用Hibernate操作資料庫時,Hibernate自動建立的。第1個外鍵的On delete被設定為No action,因此刪除“廣東”的時候,受到這個外鍵的限制,導致刪除失敗。
2、設定cascade屬性為delete-orphan
在對應檔Province.hbm.xml中,在one-to-many關係對應的Set裡,設定cascade="delete-orphan",此功能與MySQL裡設定外鍵設定為on delete cascade相同。再用方法delete()刪除“廣東”,刪除成功。即是,設定cascade為delete-orphan以後,對刪除父表記錄的時候,會同時刪除子表的相關記錄。
3、設定cascade屬性為all
cascade的屬性,除了可以是delete-orphan,還可以是create、update、delete、all等等。all代表除 delete-orphan以外的所有屬性值,當設定cascade為all以後,對父表記錄的增加、修改操作,會影響到子表的相關記錄。
在對應檔Province.hbm.xml中,在one-to-many關係對應的Set裡,設定cascade="all"。用方法 addInCascadeOfAll()增加記錄“廣東”,方法裡只有save“廣東”,並沒有save“深圳”,只是用屬性關聯了“廣東”和“深圳”的關係。結果顯示,深圳也被添加到資料庫裡,這就是cascade="all"的作用,使對父表的操作影響到子表。
注意:A、delete-orphan是一個特別的屬性值,只能應用在one-to-many關係的cascade屬性。B、cascade屬性通常在one-to-one和one-to-many關係裡應用,不推薦在many-to-one或者many-to- many關係裡應用。
三、總結
1、MySQL裡設定cascade和在Hibernate設定cascade是不同的。在MySQL裡設定了cascade,並不能對Hibernate的操作起到作用,原因是Hibernate自動為子表添加了外鍵。
2、使用級聯(cascade)功能,方便了資料庫的操作,使得操作一個表的記錄會影響到其他表的記錄。但是,級聯功能會帶來安全隱患。特別是在 Hibernate裡,修改一個POJO對象的映射引用屬性,會導致該引用屬性所對應的POJO對象受到影響。例如,把“廣東”的 Set<City>類型的cities屬性清空(即對集合Set調用clear()方法),則會導致把引用“廣東”的“深圳”刪除了。因此,使用級聯功能時要小心謹慎。