以訂單和訂單項為例來講解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<OrderItem> orderItems=new HashSet<OrderItem>();//描述一個訂單可以有多個訂單項
private Integer initOrderItems = 0;//0:懶加載 ,1:立即加載
public Integer getInitOrderItems() {
return initOrderItems;
}
public void setInitOrderItems(Integer initOrderItems) {
this.initOrderItems = initOrderItems;
}
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> 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"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class table="t_hibernate_order" name="com.zking.four.entity.Order">
<id name="orderId" type="java.lang.Integer" column="order_id">
<generator class="increment"></generator>
</id>
<property name="orderNo" type="java.lang.String" column="order_no"></property>
<!--
cascade:配置的是級聯關系
inverse:反方,是否将關聯關系交給對方控制
-->
<set name="orderItems" cascade="save-update" inverse="true">
<!-- 配置外鍵字段 -->
<key column="oid"></key>
<!-- 配置外鍵關聯的類 -->
<one-to-many class="com.zking.four.entity.OrderItem"/>
</set>
</class>
</hibernate-mapping>
OrderItem.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>
<class table="t_hibernate_order_item" name="com.zking.four.entity.OrderItem">
<id name="orderItemId" type="java.lang.Integer" column="order_item_id">
<generator class="increment"></generator>
</id>
<property name="productId" type="java.lang.Integer" column="product_id"></property>
<property name="quantity" type="java.lang.Integer" column="quantity"></property>
<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>
</hibernate-mapping>
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);
}