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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值