Hibernate深入理解----04關聯關系(單向多對1,雙向1對多)
來源:程序員人生 發布時間:2016-10-17 15:44:53 閱讀次數:2502次
參考代碼下載github:https://github.com/changwensir/java-ee/tree/master/hibernate4
?在領域模型中, 類與類之間最普遍的關系就是關聯關系.在UML圖中,關聯是有方向的
1.單向多對1
兩個類,多個Order對應1個Customer
public class Customer {
private Integer customerId;
private String customerName;
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToOne.pojo">
<class name="Customer" table="customers">
<id name="customerId" column="customer_id" type="java.lang.Integer">
<generator class="native" />
</id>
<property name="customerName" column="customer_name" type="java.lang.String"/>
</class>
</hibernate-mapping>
Order類
public class Order {
private Integer orderId;
private String orderName;
private Customer customer;
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToOne.pojo">
<class name="Order" table="orders">
<id name="orderId" type="java.lang.Integer">
<column name="order_id" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="order_name" />
</property>
<!--多個Order對應1個Customer
映照多對1的關聯關系。 使用 many-to-one 來映照多對1的關聯關系
name: 多對1端關聯的1那真個屬性的名字
class: 1那真個屬性對應的類名
column: 1那端在多的1端對應的數據表中的外鍵的名字,隨便取
-->
<many-to-one name="customer" class="Customer" column="customer_ID"/>
</class>
</hibernate-mapping>
然后把兩個hbm.xml映照到cfg.xml里
測試:before,after的見前面的內容
@Test
public void testMany2OneSave(){
Customer customer = new Customer();
customer.setCustomerName("BB");
Order order1 = new Order();
order1.setOrderName("ORDER⑶");
Order order2 = new Order();
order2.setOrderName("ORDER⑷");
//設定關聯關系
order1.setCustomer(customer);
order2.setCustomer(customer);
//這類寫法更好
//履行 save 操作: 先插入 Customer, 再插入 Order, 3 條 INSERT
//先插入 1 的1端, 再插入 n 的1端, 只有 INSERT 語句.
//推薦先插入 1 的1端, 后插入 n 的1端
session.save(customer);
session.save(order1);
session.save(order2);
//先插入 Order, 再插入 Customer. 3 條 INSERT, 2 條 UPDATE
//先插入 n 的1端, 再插入 1 的1端, 會多出 UPDATE 語句!
//由于在插入多的1端時, 沒法肯定 1 的1真個外鍵值. 所以只能等 1 的1端插入后, 再額外發送 UPDATE 語句.
/* sessionPojo.save(order1);
sessionPojo.save(order2);
sessionPojo.save(customer);*/
}
@Test
public void testMany2OneGet(){
//結論1. 若查詢多的1真個1個對象, 則默許情況下, 只查詢了多的1真個對象.
// 而沒有查詢關聯的1 的那1真個對象!
// Order order = (Order) sessionPojo.get(Order.class, 8);
// System.out.println(order.getOrderName());
//結論2. 在需要使用到關聯的對象時, 才發送對應的 SQL 語句.
// Customer customer = order.getCustomer();
// System.out.println(customer.getCustomerName());
//上面1,2的輸出結果順序是:sql語句-->sout-->sql語句-->sout
//3. 在查詢 Customer 對象時, 由多的1端導航到 1 的1端時,
//若此時 sessionPojo 已被關閉, 則默許情況下會產生 LazyInitializationException 異常
// Order order2 = (Order) session.get(Order.class, 8);
// System.out.println(order2.getOrderName());
// session.close(); //這里測試時需要把destory()方法里的transaction和session注解掉
// Customer customer2 = order2.getCustomer();
// System.out.println(customer2.getCustomerName());
//上面3的輸出結果順序是:sql語句-->order2.getOrderName()-->異常
//4. 獲得 Order 對象時, 默許情況下, 其關聯的 Customer 對象是1個代理對象!
Order order3 = (Order) session.get(Order.class, 8);
System.out.println(order3.getCustomer().getClass().getName());
}
@Test
public void testDelete(){
//在不設定級聯關系的情況下, 且 1 這1真個對象有 n 的對象在援用, 不能直接刪除 1 這1真個對象
Customer customer = (Customer) session.get(Customer.class, 8);
session.delete(customer); //不能刪除
}
@Test
public void testUpdate(){
Order order = (Order) session.get(Order.class, 8);
order.getCustomer().setCustomerName("AAA"); //有對應的update的語句
}
2、雙向1對多
Order類與上面的配置1樣,Customer類修改以下
public class Customer {
private Integer customerId;
private String customerName;
/**
* 1.聲明集合類型時,需使用接口類型。由于hibernate 在獲得集合類型時,
* 返回的是Hibernate 內置的集合類型,而不是JavaSE 1個標準集合實現
* 2.需要把集合進行初始化,可以避免空指針異常
*/
private Set<Order> orders = new HashSet<Order>();
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToManyBoth.pojo">
<class name="Customer" table="customers">
<id name="customerId" column="customer_id" type="java.lang.Integer">
<generator class="native" />
</id>
<property name="customerName" column="customer_name" type="java.lang.String"/>
<!--
映照1對多的那個集合屬性
name是Customer類里屬性,table是Order.hbm.xml里的<class name="Order" table="orders">的table里的值
外鍵column跟Order.hbm.xml里 <many-to-one里的column里值1樣\
inverse 屬性的來決定是由雙向關聯的哪1方來保護表和表之間的關系
cascade 設置級聯屬性,開發時不建議設置該屬性,建議使用手工的方式來處理
order-by 在查詢時對集合的元素進行排序,order-by 中使用的是表的字段名,而不是類的屬性名
-->
<set name="orders" table="orders" inverse="true" cascade="delete">
<key column="customer_ID2"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
把hbm.xml配置到cfg.xml里
/**
* 在hibernate.hbm.xml中通過對 inverse 屬性的來決定是由雙向關聯的哪1方來保護表和表之間的關系.
* inverse = false 的為主動方,inverse = true 的為被動方, 由主動方負責保護關聯關系
*
* 在沒有設置 inverse=true 的情況下,父子兩邊都保護父子關系
*
* 在 1-n 關系中,將 n 方設為主控方將有助于性能改良!!
*/
@Test
public void testOneToManyBothSave(){
Customer customer1 = new Customer();
customer1.setCustomerName("AA");
Order order1 = new Order();
order1.setOrderName("ORDER⑴");
Order order2 = new Order();
order2.setOrderName("ORDER⑵");
//設定關聯關系
order1.setCustomer(customer1);
order2.setCustomer(customer1);
customer1.getOrders().add(order1);
customer1.getOrders().add(order2);
/* 在沒有設置inverse的情況下:先插入 Customer, 再插入 Order, 3 條 INSERT, 2 條update
由于1的那端和n的那端都保護關聯關系,所有會多出update
如果在1的那端設置inverse=true,讓1的那端放棄保護關系,則只有3條insert!!
建議設定set的invest=true,建議先插入1的那端,再插入多的那端
*/
session.save(customer1);
session.save(order1);
session.save(order2);
// 在沒有設置inverse的情況下:先插入 Order, 再插入 Customer. 3 條 INSERT, 4 條 UPDATE
/* sessionPojo.save(order1);
sessionPojo.save(order2);
sessionPojo.save(customer1);*/
}
get,update,delete與上面類似
@Test
public void testUpdate(){
Customer customer = (Customer) session.get(Customer.class,1);
customer.getOrders().iterator().next().setOrderName("BBB");
}
@Test
public void testCascade() {
Customer customer = (Customer) session.get(Customer.class, 8);
customer.getOrders().clear();
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈