http://c.biancheng.net/view/4207.html(源網址)
在 Hibernate 的關聯關係中,可以使用單向關聯關係,也可以使用雙向關聯關係,在雙向關聯關係中,Hibernate 會同時控制雙方的關係,這樣在程序操作時,很容易出現重複操作的問題。
爲了解決這一問題,Hibernate 提供了反轉操作,同時,爲了在操作多表時,主表(主控方)操作後的數據能與關聯表的數據保持一致,Hibernate 還提供了級聯操作。接下來將對這兩種操作進行詳細講解。反轉操作
在映射文件的 <set> 標籤中,有一個 inverse(反轉)屬性,它的作用是控制關聯的雙方由哪一方管理關聯關係。
inverse 屬性值是 boolean 類型的:
- 當取值爲 false(默認值)時,表示由當前這一方管理雙方的關聯關係,如果雙方 inverse 屬性都爲 false 時,雙方將同時管理關聯關係。
- 取值爲 true 時,表示當前一方放棄控制權,由對方管理雙方的關聯關係。
通常情況下,在一對多關聯關係中,會將“一”的一方的 inverse 屬性取值爲 true,即由“多”的一方維護關聯關係,否則會產生多餘的 SQL 語句;而在多對多的關聯關係中,任意設置一方的 inverse 屬性爲 true 即可。通常情況下,這種問題有兩種解決方案:第一種是進行單向關聯,第二種是在一方的映射文件中,將 <set> 標籤的 inverse 屬性設置爲 true。
/*
* 設置雙向的關聯,產生了多餘的SQL語句
* 原來2號聯繫人屬於一號客戶。現在改爲屬於2號
* */
@Test
public void demo6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = session.get(Customer.class, 2l);
LinkMan linkMan = session.get(LinkMan.class, 1l);
/*設置雙向關聯,產生了兩次更新外鍵的語句,
* 結局方案:
* 1、在一的一方設置外鍵維護權,放棄外鍵維護權 set配置inverse=“true”
* 2、設置單向關聯
* */
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
tx.commit();
}
級聯操作
級聯操作是指當主控方執行任意操作時,其關聯對象也執行相同的操作,保持同步。在映射文件的 <set> 標籤中有個 cascade 屬性,該屬性用於設置是否對關聯對象採用級聯操作,其常用屬性如表 1 所示。
瞭解了 cascade 的相關屬性後,下面通過案例講解 cascade 屬性在實際應用中的級聯操作。
表 1 cascade屬性的屬性值 屬性值 描 述 save-update 在執行 save、update 或 saveOrUpdate 吋進行關聯操作 delete 在執行 delete 時進行關聯操作 delete-orphan 刪除所有和當前解除關聯關係的對象 all 所有情況下均進行關聯操作,但不包含 delete-orphan 的操作 all-delete-orphan 所有情況下均進行關聯操作 none 所有情況下均不進行關聯操作,這是默認值
1.如果沒有設置級聯操作,我們就要建立雙向的關聯。對於一對多的關係,我們應該在一的一方,通過集合將多的一方添加至其中,對於多的一方,通過一的一方的對象來設置。如demo實例。
2.設置級聯操作後,我們只需通過保存一方的數據即可。如demo2實例。
3.級聯保存或更新demo3。
4.級聯刪除demo5。
//保存兩個客戶、三個聯繫人 並建立關係
public void demo(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//創建兩客戶
Customer customer1 = new Customer();
customer1.setCust_name("小明");
Customer customer2 = new Customer();
customer2.setCust_name("小華");
//創建三個聯繫人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("abc");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("bcd");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("cde");
//設置關係
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
//保存數據
session.save(linkMan1);
session.save(linkMan2);
session.save(linkMan3);
session.save(customer1);
session.save(customer2);
tx.commit();
}
/*一對多隻保存一邊的數據不可以*/
@Test
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer1 = new Customer();
customer1.setCust_name("小明");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("cde");
//設置關係
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
//只保存一個對象會報瞬時態異常的錯誤,保存後一方爲爲持久態對象,一個爲瞬時態對象
session.save(linkMan1);
session.save(customer1);
tx.commit();
}
/*一對多的級聯操作
*級聯:操作一個對象的時候。是否會同時操作其關聯的對象
*
* 級聯是有方向性的:
*
*
* 級聯保存或更新
* 級聯刪除
* */
/*級聯保存或更新
* 保存客戶級聯聯繫人 :操作的主體是客戶,在Customer.hbm.xml配置客戶
*
* 途徑:通過配置 cascade 完成
* <set name="linkMans" cascade="save-update">
* */
@Test
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer1 = new Customer();
customer1.setCust_name("kevin");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("@kevin");
//設置關係
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
session.save(customer1);
tx.commit();
}
/*級聯保存或更新
* 保存聯繫人級聯客戶 :操作的主體是客戶,在linkMan.hbm.xml配置客戶
*
* 途徑:通過配置 cascade 完成
* <set name="linkMans" cascade="save-update">
* */
@Test
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer1 = new Customer();
customer1.setCust_name("kevin");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("@kevin");
//設置關係
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
session.save(linkMan1);
tx.commit();
}
/*
*測試對象的導航
* 前提:一對多的雙方都設置了cascade="save-update"
*/
@Test
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("kevin");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("kevin1");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("kevin2");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("kevin3");
//設置關係
linkMan1.setCustomer(customer);
customer.getLinkMans().add(linkMan2);
customer.getLinkMans().add(linkMan3);
//雙方都設置了cascade
// session.save(linkMan1);//發送 4 條insert語句
session.save(customer); //發送 3 條insert語句
tx.commit();
}
/*級聯保存或更新
*
*刪除客戶級聯刪除聯繫人
* 刪除聯繫人級聯刪除客戶:一般不用 先刪從表
* */
@Test
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//沒有級聯刪除,默認情況 會刪除客戶,修改聯繫人的外鍵
/* Customer customer = session.get(Customer.class,1l);
session.delete(customer);*/
//刪除客戶同時刪除聯繫人
/*級聯刪除
* *刪除主體客戶
* * 途徑:通過配置 cascade 完成
* <set name="linkMans" cascade="save-update,delete">
* */
Customer customer = session.get(Customer.class,1l);
session.delete(customer);
tx.commit();
}