Hibernate中的一對多&多對一&關聯&級聯
阿新 • • 發佈:2019-01-24
domain:
Customer:
package com.itheima.domain; import java.util.HashSet; import java.util.Set; public class Customer { private Integer id; private String name; //在1 的一方,表達持有多的一方的引用=>使用集合 private Set<Order> orders = new HashSet<Order>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } }
Order:
package com.itheima.domain; public class Order { private Integer id; private String name; private Customer customer; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
Customer.hbm.xml:
<?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="com.itheima.domain" > <class name="Customer" table="t_customer" > <id name="id" column="id" > <generator class="native"></generator> </id> <property name="name" column="name" type="string" ></property> <!-- 表達一對多關係中的集合 name:集合的屬性名稱 inverse: 是否將關係的維護反轉給對方. 預設值: false true: 在Customer 中 放棄維護外來鍵關係 cascade :級聯操作 save-update:級聯儲存,級聯修改. 儲存A時,同時儲存B. delete:刪除A,同時刪除B,AB都不存在 delete-orphan:孤兒刪除,解除關係,同時將B刪除,A存在的。 如果需要配置多項,使用逗號分隔。<set cascade="save-update,delete"> all : save-update 和 delete 整合 all-delete-orphan : 三個整合 --> <set name="orders" inverse="false" cascade="all-delete-orphan" > <!-- key 用來描述外來鍵 column : 外來鍵的值 --> <key column="cid" ></key> <!-- one-to-many 表達, Customer 與orders 的關係是一對多 class: 表達關聯的另一方的完整類名 --> <one-to-many class="Order" /> </set> </class> </hibernate-mapping>
Order.hbm.xml:
<?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="com.itheima.domain" >
<class name="Order" table="t_order" >
<id name="id" column="id" >
<generator class="native"></generator>
</id>
<property name="name" column="name" type="string" ></property>
<!-- 表達多對一關係
name: 引用的屬性名稱
column: 外來鍵的列名
class: 我引用的Order的完整類名
-->
<many-to-one name="customer" column="cid" class="Customer" ></many-to-one>
</class>
</hibernate-mapping>
hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- property 元素用於配置Hibernate中的屬性
鍵:值
-->
<!-- hibernate.connection.driver_class : 連線資料庫的驅動 -->
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- hibernate.connection.username : 連線資料庫的使用者名稱 -->
<property name="hibernate.connection.username">root</property>
<!-- hibernate.connection.password : 連線資料庫的密碼 -->
<property name="hibernate.connection.password">1234</property>
<!-- hibernate.connection.url : 連線資料庫的地址,路徑 -->
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/EE19Day02
</property>
<!-- show_sql: 操作資料庫時,會 向控制檯列印sql語句 -->
<property name="show_sql">true</property>
<!-- format_sql: 列印sql語句前,會將sql語句先格式化 -->
<property name="format_sql">true</property>
<!-- hbm2ddl.auto: 生成表結構的策略配置
update(最常用的取值): 如果當前資料庫中不存在表結構,那麼自動建立表結構.
如果存在表結構,並且表結構與實體一致,那麼不做修改
如果存在表結構,並且表結構與實體不一致,那麼會修改表結構.會保留原有列.
create(很少):無論是否存在表結構.每次啟動Hibernate都會重新建立表結構.(資料會丟失)
create-drop(極少): 無論是否存在表結構.每次啟動Hibernate都會重新建立表結構.每次Hibernate執行結束時,刪除表結構.
validate(很少):不會自動建立表結構.也不會自動維護表結構.Hibernate只校驗表結構. 如果表結構不一致將會丟擲異常.
-->
<property name="hbm2ddl.auto">update</property>
<!-- 資料庫方言配置
org.hibernate.dialect.MySQLDialect (選擇最短的)
-->
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- hibernate.connection.autocommit: 事務自動提交
<property name="hibernate.connection.autocommit">true</property>
-->
<!-- 將Session與執行緒繫結=> 只有配置了該配置,才能使用getCurrentSession -->
<property name="hibernate.current_session_context_class">
thread
</property>
<!-- 引入ORM 對映檔案
填寫src之後的路徑
-->
<mapping resource="com/itheima/domain/User.hbm.xml" />
<mapping resource="com/itheima/domain/Customer.hbm.xml" />
<mapping resource="com/itheima/domain/Order.hbm.xml" />
</session-factory>
</hibernate-configuration>
一對多關係:
package com.itheima.e_one2many;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
import com.itheima.domain.Customer;
import com.itheima.domain.Order;
import com.itheima.utils.HibernateUtils;
//測試 一對多關係
public class Demo1 {
@Test
//1 測試1對多關係中,儲存操作
//共列印5條語句
//前3條列印insert => 儲存物件,維護外來鍵
//後兩條列印update => 維護外來鍵
//解決=> 單純指定 關係由其中一方來維護.另一方不維護關係.
//注意=> 外來鍵維護的放棄,只能由非外來鍵所在物件來放棄.
//Customer inverse屬性: true
//只打印3條語句=> 外來鍵由order自己來維護
public void fun1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = new Customer();
c.setName("tom");
Order o1 = new Order();
o1.setName("肥皂");
Order o2 = new Order();
o2.setName("蠟燭");
//c.getOrders().add(o1);//維護關係
//c.getOrders().add(o2); //維護關係
o1.setCustomer(c);//維護關係
o2.setCustomer(c);//維護關係
session.save(c);//儲存物件
session.save(o1);//儲存物件
session.save(o2);//儲存物件
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
//多表關係=> 刪除
//刪除 使用者時 ,會先移除 Customer中引用的外來鍵.然後再刪除Customer
// 結論: 維護一方的物件時,會自動維護另一方的關係
// Customer 的 inverse屬性: true
// 會報錯 => Customer不負責維護外來鍵, 直接刪除Customer 會導致,order引用了無效的id.違反了外來鍵約束.
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 3);
// Customer 的 inverse屬性: true
Set<Order> set = c.getOrders();
for(Order o : set){
o.setCustomer(null);//設定訂單不屬於任何Customer
}
session.delete(c);
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
//什麼時候配置inverse屬性?
// 主要看業務. 如果一的一方經常需要維護外來鍵 = 在1的一方不要配置inverse屬性.
}
級聯儲存和修改:
package com.itheima.e_one2many;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
import com.itheima.domain.Customer;
import com.itheima.domain.Order;
import com.itheima.utils.HibernateUtils;
//測試 一對多關係 級聯儲存 級聯修改
public class Demo2 {
@Test
//增
//我們希望在儲存Customer時,自動將未儲存的Orders當中的Order儲存
//cascade: save-update
public void fun1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = new Customer();
c.setName("tom");
Order o1 = new Order();
o1.setName("肥皂");
Order o2 = new Order();
o2.setName("蠟燭");
c.getOrders().add(o1);//維護關係
c.getOrders().add(o2); //維護關係
/*
o1.setCustomer(c);//維護關係
o2.setCustomer(c);//維護關係
*/
session.save(c);//儲存物件
//session.save(o1);//儲存物件
//session.save(o2);//儲存物件
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
@Test
//增
//我們希望在儲存Customer時,自動將未儲存的Orders當中的Order儲存
//cascade: save-update
public void fun2(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 8);//1條 select
for(Order o :c.getOrders()){ // 1條 select
o.setName("哇哈哈"); // 修改訂單
}
//------------------------------------------------
session.getTransaction().commit();//因為設定級聯修改,自動將訂單的修改儲存到資料
//update語句
session.close(); // 遊離狀態
}
@Test
//cascade: delete
//刪除Customer時 ,會將Customer下的訂單一併刪除
//inverse : false 6條sql語句
//inverse : true 5條sql語句 比上面少一條維護外來鍵
public void fun3(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 7);//1條 select
session.delete(c);//刪除Customer
// 刪除兩個Order
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
@Test
//cascade: delete
//操作的兩方cascade值都為delete
//需要注意: 千萬不要在兩方都配置 級聯刪除. 刪除任何一方,會導致整個關係鏈物件全部刪除.
public void fun4(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Order o = (Order) session.get(Order.class, 9);//select
session.delete(o);//delete刪除當前order
//找到所有關聯的Customer刪除 select
// delete Customer
// Customer配置了級聯刪除=> select 找下面的order
// 刪除所有Order
//刪除Customer
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
}
級聯刪除:孤兒刪除:
package com.itheima.e_one2many;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
import com.itheima.domain.Customer;
import com.itheima.domain.Order;
import com.itheima.utils.HibernateUtils;
//測試 一對多關係
public class Demo3 {
@Test
//inverse:false
//cascade: delete-orphan 孤兒刪除 => 當沒有任何外來鍵引用Order時,order 會被刪除
public void fun1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 9);
Iterator<Order> it = c.getOrders().iterator();
//注意: 刪除Customer下的訂單時,不能使用 c.setOrders(null); c.setOrders(new HashSet());
while(it.hasNext()){ // 遍歷Customer下的訂單,並將訂單刪除 => 維護關係
it.next();
it.remove();
}
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
}
級聯刪除:整合:
package com.itheima.e_one2many;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
import com.itheima.domain.Customer;
import com.itheima.domain.Order;
import com.itheima.utils.HibernateUtils;
//測試 一對多關係
public class Demo4 {
@Test
//cascade: all-delete-orphan => 相當於配置 save-update,delete,delete-orphan
public void fun1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = new Customer();
c.setName("tom");
Order o1 = new Order();
o1.setName("肥皂");
Order o2 = new Order();
o2.setName("蠟燭");
c.getOrders().add(o1);//維護關係
c.getOrders().add(o2); //維護關係
session.save(c);
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
@Test
//cascade: all-delete-orphan => 相當於配置 save-update,delete,delete-orphan
public void fun2(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 10);
session.delete(c);
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
@Test
//cascade: all-delete-orphan => 相當於配置 save-update,delete,delete-orphan
public void fun3(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 12);
Iterator<Order> it = c.getOrders().iterator();
while(it.hasNext()){ // 遍歷Customer下的訂單,並將訂單刪除 => 維護關係
it.next();
it.remove();
}
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 遊離狀態
}
}