save-update: 級聯儲存(load以後如果子物件發生了更新,也會串聯更新). 但它不會串聯刪除
delete: 串聯刪除, 但不具備級聯儲存和更新
all-delete-orphan: 在解除父子關係時,自動刪除不屬於父物件的子物件, 也支援串聯刪除和級聯儲存更新.
all: 串聯刪除, 串聯更新,但解除父子關係時不會自動刪除子物件.
delete-orphan:刪除所有和當前對象解除關聯關係的對象
注意:以上設在哪一段就是指對哪一端的操作而言,比如delete,如果設在one的一端的<set>屬性裡,就是當one被刪除的時候,自動刪除所有的子記錄;
如果設在many一端的<many-to-one>標籤裡,就是在刪除many一端的資料時,會試圖刪除one一端的資料,如果仍然有many外鍵引用one,就會報“存在子記錄”的錯誤;如果在one的一端同時也設定了cascade=“delete”屬性,就會發生很危險的情況:刪除many一端的一條記錄,會試圖串聯刪除對應的one端記錄,因為one也設定了串聯刪除many,所以其他所有與one關聯的many都會被刪掉。
所以,千萬謹慎在many一端設定cascade=“delete”屬性。
故此cascade一般用在<one-to-one>和<one-to-many>中
one-to-many中設定串聯刪除,比如:
<set<br /> name="entryvalues"<br /> lazy="false"<br /> inverse="true"<br /> order-by="VALUEID"<br /> cascade="all-delete-orphan"<br /> ><br /> <key><br /> <column name="CONTEXTENTRYID" /><br /> </key><br /> <one-to-many<br /> class="Entryvalue"<br /> /><br /> </set><br />
如果用Hiberante的SchemaExport匯出表到資料庫,是不會在資料庫中設定外鍵的cascade屬性的,查看ENTRYVALUE表,其中的外鍵CONTEXTENTRYID的on delete屬性是no action
但是使用Hiberante管理事務,它是會維護這種級聯關係的,比如這樣操作:
public void testCascadeDelete() {<br />Session s = HibernateUtil.getSession();<br />Transaction tx;<br />try {<br />tx = s.beginTransaction();<br />Contextentry ce = (Contextentry)s.load(Contextentry.class, new Long(1));</p><p>s.delete(ce);<br />tx.commit();</p><p>} catch (HibernateException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />}<br />}
則引用此Contextentry的Entryvalue是會被正確串聯刪除的.
如果使用普通JDBC操作,比如:
public void testCascadeDeleteSQL() {<br />Session s = HibernateUtil.getSession();<br />Transaction tx;<br />String sql = "delete contextentry where id=4";<br />try {<br />tx = s.beginTransaction();<br />Connection con = s.connection();<br />Statement st = con.createStatement();<br />st.execute(sql);<br />tx.commit();<br />} catch (HibernateException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />} catch (SQLException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />}<br />}
則會報"存在子記錄"的錯誤,這裡的Transaction實際上是無效的,因為用的是JDBC的Connection和Statement,已經脫離了Hibernate的管理.如果手動將ENTRYVALUE表的相關外鍵ON DELETE屬性設為CASCADE,則上面的操作當然正確執行——串聯刪除子記錄
all-delete-orphan 的能力:
1. 當儲存或更新父方對象時,級聯儲存或更新所有關聯的子方對象,相當於 cascade 為 save-update
2. 當刪除父方對象時,串聯刪除所有關聯的子方對象,相當於 cascade 為 delete
3. 刪除不再和父方對象關聯的所有子方對象,當然,“不再和父方對象關聯的所有子方對象”必須是在本次事務中發生的。
解除父子關係的 java 語句例如:
public void testCascadeDelete() {<br />Session s = HibernateUtil.getSession();<br />Transaction tx;<br />try {<br />tx = s.beginTransaction();<br />Contextentry ce = (Contextentry)s.load(Contextentry.class, new Long(5));</p><p>Entryvalue ev = (Entryvalue)s.load(Entryvalue.class, new Long(10));<br />ev.setContextentry(null);</p><p>s.delete(ce);<br />tx.commit();</p><p>} catch (HibernateException e) {<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />}<br />}
如果 cascade 屬性取預設值 null,當解除父子關係時,會執行如下 sql:
update ENTRYVALUE set CONTEXTENTRYID=null where ID=10
即將對應外鍵置為null,而使用all-delete-orphan,則會在相關事務執行的時候,將孤兒子記錄刪除