1. 程式人生 > >Hibernate中的一對多&多對一&關聯&級聯

Hibernate中的一對多&多對一&關聯&級聯

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(); // 遊離狀態
	}
}