hibernate關聯對映之一對多關係
以訂單和訂單項為例來講解Hibernate關聯對映中的一對多關聯關係。兩個實體類如下:
訂單類:
package com.zking.four.entity;
import java.util.HashSet; import java.util.Set;
/**
-
訂單實體類(一對多中的一)
-
@author LJ
-
@Date 2018年10月23日
-
@Time 下午10:08:48 */ public class Order {
private Integer orderId;//訂單ID(主鍵) private String orderNo;//訂單編號
private Set orderItems=new HashSet();//描述一個訂單可以有多個訂單項 private Integer initOrderItems = 0;//0:懶載入 ,1:立即載入
public Integer getInitOrderItems() { return initOrderItems; } public void setInitOrderItems(Integer initOrderItems) { this.initOrderItems = initOrderItems; } public Set getOrderItems() { return orderItems; } public void setOrderItems(Set orderItems) { this.orderItems = orderItems; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; }
} 訂單項類:
package com.zking.four.entity;
/**
-
訂單項實體類(一對多中的多)
-
@author LJ
-
@Date 2018年10月23日
-
@Time 下午10:08:25 */ public class OrderItem {
private Integer orderItemId;//訂單項ID(主鍵) private Integer productId;//商品ID private Integer quantity;//數量 private Integer oid;//訂單ID(外來鍵)
private Order order;//訂單項與訂單關聯,描述訂單項屬於某個訂單
public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } public Integer getOrderItemId() { return orderItemId; } public void setOrderItemId(Integer orderItemId) { this.orderItemId = orderItemId; } public Integer getProductId() { return productId; } public void setProductId(Integer productId) { this.productId = productId; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getOid() { return oid; } public void setOid(Integer oid) { this.oid = oid; } } Order.hbm.xml配置檔案:
<property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"></property>
<many-to-one name="order" class="com.zking.four.entity.Order" column="oid"></many-to-one>
</class>
1、級聯新增
/**
* 新增訂單項表
* @author LJ
* @Date 2018年10月23日
* @Time 下午8:03:18
* @param orderItem
* @return
*/
public Integer saveOrderItem(OrderItem orderItem) {
Session session = SessionFactoryUtil.getSession();//獲取session
Transaction transaction = session.beginTransaction();//開啟事務
Integer oid = (Integer) session.save(orderItem);//新增訂單項
transaction.commit();//提交事務
SessionFactoryUtil.closeSession();//關閉session
return oid;
}
@Test
public void testSaveOrderItem() {
OrderItem orderItem=new OrderItem();
Order order=new Order();
order.setOrderId(1);
orderItem.setOrder(order);
orderItem.setProductId(3);
orderItem.setQuantity(45);
this.saveOrderItem(orderItem);
}
若不對外來鍵進行處理的話,會出現異常java.lang.ExceptionInInitializerError,這一異常導致的原因是Repeated column in mapping for entity: com.zking.four.entity.OrderItem column: oid (should be mapped with insert=“false” update=“false”),也就是因為OrderItem.hbm.xml配置檔案裡對外來鍵重複配置了,所以才出現的異常
解決方式:a、刪除從表對應的實體類中的外來鍵屬性 b、在配置的xml中外來鍵屬性上新增 insert=false,update=false的設定。 c、在配置的xml中的manyToOne標籤中新增insert=false,update=false的設定。我這裡選的是第二種方式
/**
* 新增訂單表
* @author LJ
* @Date 2018年10月23日
* @Time 下午8:03:31
* @param order
* @return
*/
public Integer saveOrder(Order order) {
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Integer oid = (Integer) session.save(order);
transaction.commit();
SessionFactoryUtil.closeSession();
return oid;
}
/**
* 提交訂單中含有5個訂單項的方法
* @author LJ
* @Date 2018年10月23日
* @Time 下午5:40:05
*/
@Test
public void testSaveOrder() {
Order order=new Order();
order.setOrderNo("2");
OrderItem orderItem;
for (int i = 1; i < 6; i++) {
orderItem=new OrderItem();
orderItem.setProductId(i);
orderItem.setQuantity(i);
orderItem.setOrder(order);
order.getOrderItems().add(orderItem);
}
this.saveOrder(order);
}
2、級聯查詢
/**
* 根據訂單編號查詢訂單
* @author LJ
* @Date 2018年10月23日
* @Time 下午8:03:39
* @param order
* @return
*/
public Order getOrder(Order order) {
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Order o = session.get(Order.class, order.getOrderId());
transaction.commit();
SessionFactoryUtil.closeSession();
return o;
}
@Test
public void testGetOrder() {
Order order=new Order();
order.setOrderId(2);//查詢訂單編號為2的訂單
Order o = this.getOrder(order);
System.out.println(o.getOrderNo());
System.out.println(o.getOrderItems().size());
}
執行以上程式碼會發現只輸出了o.getOrderNo(),而o.getOrderItems().size()沒有輸出,而且還報了異常org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.zking.four.entity.Order.orderItems, could not initialize proxy - no Session,這是懶載入的異常,因為級聯查詢預設是懶載入,所以要等到呼叫了o.getOrderItems().size()才會執行查詢語句,但這時session已經關閉了,所以出現這一異常。
也許你會想到將lazy屬性設為false就能解決這一問題,並不是這樣,因為將lazy屬性設為false後,雖然查詢單個時不會出現異常,但查詢所有時會存在問題,就是查詢所有訂單時,它會預設把訂單下的所有訂單項也給查詢出來,但我們有時並不需要用到,所以這就浪費了資源,消耗了不該消耗的效能。綜上所述,最好的解決方式就是通過欄位控制是否需要懶載入。
3、普通刪除
大家都知道,刪除主鍵表裡的某條資料時,要先刪除外來鍵表裡的資料,所以刪除訂單時的程式碼如下:
/**
* 刪除訂單
* @author LJ
* @Date 2018年10月23日
* @Time 下午8:04:18
* @param order
*/
public void delOrder(Order order) {
Session session = SessionFactoryUtil.getSession();//獲取session
Transaction transaction = session.beginTransaction();//開啟事務
Order o = session.get(Order.class, order.getOrderId());//根據訂單ID獲取到該訂單
for (OrderItem oi : o.getOrderItems()) {//遍歷該訂單所有的訂單項
session.delete(oi);//先刪除訂單項
}
session.delete(o);//在刪除該訂單
transaction.commit();//提交事務
session.close();//關閉session
}
@Test
public void testDelOrder() {
Order order=new Order();
order.setOrderId(1);//刪除訂單編號為1的訂單
this.delOrder(order);
}