級聯保存或更新CASCADE
級聯保存或更新:
作用就是:保存一方的數據的時候,會把關聯的對象也同時保存。
級聯保存或更新的配置:
屬性名:cascade
屬性值:
1.none:所有情況下均不進行關聯操作。(默認值)
2.save-update:在執行save/update/saveOrUpdate時進行關聯操作
3.delete:在執行delete時進行關聯操作
4.all-delete-orphan:當一個節點在對象圖中成為孤兒節點時,刪除該節點
5.all:所有情況下均進行關聯操作,即save-update和delete(但是不推薦,避免刪除后級聯刪除最后導致莫名其妙少了很多數據)
先貼上一段代碼:
這段代碼是上一章的代碼,作用是創建新用戶並且創建兩個訂單添加到該客戶中。
新創建的對象都是瞬時狀態,我們保存到數據庫需要將對象進行持久化操作。
這里發現,最后持久化對象用了三行代碼。
session.save(cst); session.save(od); session.save(od1);
又保存客戶,又保存兩個訂單,感覺代碼有點多。但是不執行后兩個行代碼又不行,瞬時狀態的怎么可以!
所以我們就得設置級聯操作了,這樣就可以保存某一方的同時,自動保存或更新級聯的對象。
/** * 創建新用戶並且創建兩個訂單添加到該客戶中 */ @Test public void fun1(){ Session session = HibernateUtils.getSession(); session.getTransaction().begin(); try { //新建用戶 瞬時狀態
Customer cst = new Customer(); cst.setCust_id(1); cst.setCust_name("台用勝"); cst.setCust_gender("男"); cst.setCust_age(24); cst.setCust_phone("18736549531"); //新建訂單 瞬時狀態
Order od = new Order(); od.setOrder_id(UUID.randomUUID().toString()); od.setDetail_id(UUID.randomUUID().toString()); Order od1 = new Order(); od1.setOrder_id(UUID.randomUUID().toString()); od1.setDetail_id(UUID.randomUUID().toString()); //表達客戶和訂單的關系
cst.getOds().add(od); cst.getOds().add(od1); //表達訂單和客戶的關系
od.setCst(cst); od1.setCst(cst); //持久化用戶和訂單
session.save(cst); session.save(od); session.save(od1); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); } session.getTransaction().commit(); }
級聯保存或更新的操作:
這里有客戶對訂單的關系,上述中,給客戶添加訂單需要三行代碼。
這三行代碼中, 如果我們認為客戶方是“主控方”那么后面的兩行代碼我們就可以省略,如果我們認為訂單方是“主控方”那么第一行的代碼就可以省略。具體看代碼
那我就舉一個例子,選擇客戶方是“主控方”,
1.配置Customer.hbm.xml(在配置的時候添加cascade="save-update")
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="deep.domain">
<class name="Customer" table="customera">
<id name="cust_id" column = "cust_id">
<generator class="native"></generator>
</id>
<property name="cust_name" column = "cust_name"></property>
<property name="cust_gender" column = "cust_gender"></property>
<property name="cust_age" column = "cust_age"></property>
<property name="cust_phone" column = "cust_phone"></property>
<!-- 配置一對多屬性 -->
<set name="ods" cascade="save-update">
<key column="cust_order_id" ></key>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
2.隨后將上面粘貼的java代碼進行修改(我們會發現,少了session.save(od)和session.save(od1)),但是效果是一樣的
/** * 級聯保存或更新 * 創建新用戶並且創建兩個訂單添加到該客戶中 */ @Test public void fun2(){ Session session = HibernateUtils.getSession(); session.getTransaction().begin(); try { //新建用戶 瞬時狀態
Customer cst = new Customer(); cst.setCust_id(1); cst.setCust_name("台用勝"); cst.setCust_gender("男"); cst.setCust_age(24); cst.setCust_phone("18736549531"); //新建訂單 瞬時狀態
Order od = new Order(); od.setDetail_id(UUID.randomUUID().toString()); Order od1 = new Order(); od1.setDetail_id(UUID.randomUUID().toString()); //表達客戶和訂單的關系
cst.getOds().add(od); cst.getOds().add(od1); //表達訂單和客戶的關系
od.setCst(cst); od1.setCst(cst); //持久化用戶和訂單
session.save(cst); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); } session.getTransaction().commit(); }
同樣,如果我們認為訂單方是“主控方”,那么就只要這樣配置
<!-- 配置多對一屬性 -->
<many-to-one name="cst" class="Customer" column="cust_order_id" cascade="save-update" />
隨后的java代碼是:(獲取主鍵值為 6的客戶,並新建兩個訂單添加到該客戶中)
/** * 級聯保存或更新 * 獲取用戶並且創建兩個訂單添加到該客戶中 */ @Test public void fun3(){ Session session = HibernateUtils.getSession(); session.getTransaction().begin(); try { //獲取主鍵值為6的客戶 瞬時狀態
Customer cst = session.get(Customer.class, 6); //新建訂單 瞬時狀態
Order od = new Order(); od.setDetail_id(UUID.randomUUID().toString()); Order od1 = new Order(); od1.setDetail_id(UUID.randomUUID().toString()); //表達客戶和訂單的關系
cst.getOds().add(od); cst.getOds().add(od1); //表達訂單和客戶的關系
od.setCst(cst); od1.setCst(cst); //持久化用戶和訂單
session.save(od); session.save(od1); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); } session.getTransaction().commit(); }
剛剛上面的是兩種單一方向,也可以認為訂單方和客戶方都是“主控方”,方法自然很簡單,就是在兩邊都加上cascade="save-update"啦~
到這里cascade概念基本可以了,我也算是有點理解了吧,這樣確實方便很多,少了代碼量,也比較人性化。
問題:我的訂單表中的主鍵這是的是uuid,在配置文件中設置了主鍵自增策略是uuid,在創建新訂單的時候,我有一個訂單.setId的動作,並且手動生成了uuid。 在我沒有級聯操作的時候,能夠正常添加訂單,但是級聯操作后就會報錯,java代碼和報錯代碼如下(我認為客戶方是“主控方”)
錯誤明細:
十一月 18, 2018 4:31:07 下午 org.hibernate.internal.SessionImpl$5 mapManagedFlushFailure
ERROR: HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]
百度查了也沒搞懂是怎么回事,想了有一會兒,然后報錯,看到錯誤來源sql語句update的第一個參數,我就看到了我java中,然后猜測是主鍵策略方面的問題,我就嘗試把那一行代碼刪除,發現可以運行,但是不知道為什么。如果有大佬知道希望能指點一二。。謝謝啦~