1. 程式人生 > >hibernate關聯對映之一對多關係

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配置檔案:

<?xml version="1.0" encoding="UTF-8"?> OrderItem.hbm.xml配置檔案: <?xml version="1.0" encoding="UTF-8"?>
	<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);
}