Hibernate深入理解----04關(guān)聯(lián)關(guān)系(單向多對(duì)1,雙向1對(duì)多)
來源:程序員人生 發(fā)布時(shí)間:2016-10-17 15:44:53 閱讀次數(shù):2499次
參考代碼下載github:https://github.com/changwensir/java-ee/tree/master/hibernate4
?在領(lǐng)域模型中, 類與類之間最普遍的關(guān)系就是關(guān)聯(lián)關(guān)系.在UML圖中,關(guān)聯(lián)是有方向的
1.單向多對(duì)1
兩個(gè)類,多個(gè)Order對(duì)應(yīng)1個(gè)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>
<!--多個(gè)Order對(duì)應(yīng)1個(gè)Customer
映照多對(duì)1的關(guān)聯(lián)關(guān)系。 使用 many-to-one 來映照多對(duì)1的關(guān)聯(lián)關(guān)系
name: 多對(duì)1端關(guān)聯(lián)的1那真?zhèn)€屬性的名字
class: 1那真?zhèn)€屬性對(duì)應(yīng)的類名
column: 1那端在多的1端對(duì)應(yīng)的數(shù)據(jù)表中的外鍵的名字,隨便取
-->
<many-to-one name="customer" class="Customer" column="customer_ID"/>
</class>
</hibernate-mapping>
然后把兩個(gè)hbm.xml映照到cfg.xml里
測(cè)試:before,after的見前面的內(nèi)容
@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⑷");
//設(shè)定關(guān)聯(lián)關(guān)系
order1.setCustomer(customer);
order2.setCustomer(customer);
//這類寫法更好
//履行 save 操作: 先插入 Customer, 再插入 Order, 3 條 INSERT
//先插入 1 的1端, 再插入 n 的1端, 只有 INSERT 語(yǔ)句.
//推薦先插入 1 的1端, 后插入 n 的1端
session.save(customer);
session.save(order1);
session.save(order2);
//先插入 Order, 再插入 Customer. 3 條 INSERT, 2 條 UPDATE
//先插入 n 的1端, 再插入 1 的1端, 會(huì)多出 UPDATE 語(yǔ)句!
//由于在插入多的1端時(shí), 沒法肯定 1 的1真?zhèn)€外鍵值. 所以只能等 1 的1端插入后, 再額外發(fā)送 UPDATE 語(yǔ)句.
/* sessionPojo.save(order1);
sessionPojo.save(order2);
sessionPojo.save(customer);*/
}
@Test
public void testMany2OneGet(){
//結(jié)論1. 若查詢多的1真?zhèn)€1個(gè)對(duì)象, 則默許情況下, 只查詢了多的1真?zhèn)€對(duì)象.
// 而沒有查詢關(guān)聯(lián)的1 的那1真?zhèn)€對(duì)象!
// Order order = (Order) sessionPojo.get(Order.class, 8);
// System.out.println(order.getOrderName());
//結(jié)論2. 在需要使用到關(guān)聯(lián)的對(duì)象時(shí), 才發(fā)送對(duì)應(yīng)的 SQL 語(yǔ)句.
// Customer customer = order.getCustomer();
// System.out.println(customer.getCustomerName());
//上面1,2的輸出結(jié)果順序是:sql語(yǔ)句-->sout-->sql語(yǔ)句-->sout
//3. 在查詢 Customer 對(duì)象時(shí), 由多的1端導(dǎo)航到 1 的1端時(shí),
//若此時(shí) sessionPojo 已被關(guān)閉, 則默許情況下會(huì)產(chǎn)生 LazyInitializationException 異常
// Order order2 = (Order) session.get(Order.class, 8);
// System.out.println(order2.getOrderName());
// session.close(); //這里測(cè)試時(shí)需要把destory()方法里的transaction和session注解掉
// Customer customer2 = order2.getCustomer();
// System.out.println(customer2.getCustomerName());
//上面3的輸出結(jié)果順序是:sql語(yǔ)句-->order2.getOrderName()-->異常
//4. 獲得 Order 對(duì)象時(shí), 默許情況下, 其關(guān)聯(lián)的 Customer 對(duì)象是1個(gè)代理對(duì)象!
Order order3 = (Order) session.get(Order.class, 8);
System.out.println(order3.getCustomer().getClass().getName());
}
@Test
public void testDelete(){
//在不設(shè)定級(jí)聯(lián)關(guān)系的情況下, 且 1 這1真?zhèn)€對(duì)象有 n 的對(duì)象在援用, 不能直接刪除 1 這1真?zhèn)€對(duì)象
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"); //有對(duì)應(yīng)的update的語(yǔ)句
}
2、雙向1對(duì)多
Order類與上面的配置1樣,Customer類修改以下
public class Customer {
private Integer customerId;
private String customerName;
/**
* 1.聲明集合類型時(shí),需使用接口類型。由于hibernate 在獲得集合類型時(shí),
* 返回的是Hibernate 內(nèi)置的集合類型,而不是JavaSE 1個(gè)標(biāo)準(zhǔn)集合實(shí)現(xiàn)
* 2.需要把集合進(jìn)行初始化,可以避免空指針異常
*/
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對(duì)多的那個(gè)集合屬性
name是Customer類里屬性,table是Order.hbm.xml里的<class name="Order" table="orders">的table里的值
外鍵column跟Order.hbm.xml里 <many-to-one里的column里值1樣\
inverse 屬性的來決定是由雙向關(guān)聯(lián)的哪1方來保護(hù)表和表之間的關(guān)系
cascade 設(shè)置級(jí)聯(lián)屬性,開發(fā)時(shí)不建議設(shè)置該屬性,建議使用手工的方式來處理
order-by 在查詢時(shí)對(duì)集合的元素進(jìn)行排序,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中通過對(duì) inverse 屬性的來決定是由雙向關(guān)聯(lián)的哪1方來保護(hù)表和表之間的關(guān)系.
* inverse = false 的為主動(dòng)方,inverse = true 的為被動(dòng)方, 由主動(dòng)方負(fù)責(zé)保護(hù)關(guān)聯(lián)關(guān)系
*
* 在沒有設(shè)置 inverse=true 的情況下,父子兩邊都保護(hù)父子關(guān)系
*
* 在 1-n 關(guān)系中,將 n 方設(shè)為主控方將有助于性能改良!!
*/
@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⑵");
//設(shè)定關(guān)聯(lián)關(guān)系
order1.setCustomer(customer1);
order2.setCustomer(customer1);
customer1.getOrders().add(order1);
customer1.getOrders().add(order2);
/* 在沒有設(shè)置inverse的情況下:先插入 Customer, 再插入 Order, 3 條 INSERT, 2 條update
由于1的那端和n的那端都保護(hù)關(guān)聯(lián)關(guān)系,所有會(huì)多出update
如果在1的那端設(shè)置inverse=true,讓1的那端放棄保護(hù)關(guān)系,則只有3條insert!!
建議設(shè)定set的invest=true,建議先插入1的那端,再插入多的那端
*/
session.save(customer1);
session.save(order1);
session.save(order2);
// 在沒有設(shè)置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();
}
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)