hibernate中一对多双向关联的记录

数据库脚本建表:

– 订单表(主表)
create table t_hibernate_order
(
order_id int primary key auto_increment,
order_no varchar(50) not null
);

– 订单项表(从表)
create table t_hibernate_order_item
(
order_item_id int primary key auto_increment,
product_id int not null,
quantity int not null,
oid int not null,
foreign key(oid) references t_hibernate_order(order_id)
);

– 加数据的代码就不贴了,自己加吧

实体的创建以及配置就不多说了,直接贴代码:

订单

package com.hibernate.entity;

import java.util.HashSet;
import java.util.Set;
/**

  • 订单实体
  • @author lenovo

*/
public class Order {

private Integer order_id; 
private String order_no; 

    /*
 * 一个订单中对应的多个订单项
 */
private Set<OrderItem> orderItems=new HashSet<>();

public Set<OrderItem> getOrderItems() {
	return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
	this.orderItems = orderItems;
}
public Integer getOrder_id() {
	return order_id;
}
public void setOrder_id(Integer order_id) {
	this.order_id = order_id;
}
public String getOrder_no() {
	return order_no;
}
public void setOrder_no(String order_no) {
	this.order_no = order_no;
}
@Override
public String toString() {
	return "Order [order_id=" + order_id + ", order_no=" + order_no + "]";
}

}
订单实体的映射配置文件

<?xml version="1.0" encoding="UTF-8"?>
	<!-- name属性为Order实体中订单项的属性名 -->
	<set name="orderItems">
		<!-- column 为订单项中外键的属性名 -->
		<key column="oid"></key>
		<!-- class为订单项的全限定名 -->
		<one-to-many class="com.hibernate.entity.OrderItem"/>
	</set>
</class>

订单项

package com.hibernate.entity;

/**

  • 订单项实体
  • @author lenovo

*/
public class OrderItem {

private Integer order_item_id;
private Integer product_id;
private Integer quantity;
    //数据库中设置的外键,与订单中的订单id关联
private Integer oid;   

/**
 * 订单项所对应的订单
 */
private Order order;

public Integer getOrder_item_id() {
	return order_item_id;
}

public void setOrder_item_id(Integer order_item_id) {
	this.order_item_id = order_item_id;
}

public Integer getProduct_id() {
	return product_id;
}

public void setProduct_id(Integer product_id) {
	this.product_id = product_id;
}

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;
}

public Order getOrder() {
	return order;
}

public void setOrder(Order order) {
	this.order = order;
}

@Override
public String toString() {
	return "OrderItem [order_item_id=" + order_item_id + ", product_id=" + product_id + ", quantity=" + quantity
			+ ", oid=" + oid + "]";
}

}
订单项实体的映射配置文件

<?xml version="1.0" encoding="UTF-8"?>
	<!-- name为实体类中订单的属性名 ,  class为订单的全限定名   ,  column 为外键的属性名   -->
	<many-to-one name="order" class="com.hibernate.entity.Order" column="oid" insert="false" update="false"></many-to-one>
	<!-- 当配置的属性属性中  column有存在同名的情况时,需设置insert="false" update="false" 否则会报错  -->
</class>

将订单于订单项的配置文件配置到hibernate的核心配置文件中:

<?xml version="1.0" encoding="UTF-8"?> root 123 jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT com.mysql.jdbc.Driver org.hibernate.dialect.MySQLDialect thread true true

编写dao方法:

package com.hibernate.dao;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.hibernate.entity.Order;
import com.hibernate.util.HibernateUtils;

public class OrderDao {
/**
* 查询订单时,对应的订单项也会一同查询出来。
* @param order
* @return
*/
public Order get(Order order) {
//HibernateUtils为自己写的一个工具类,得到会话
Session session = HibernateUtils.getSession();
//开启事务。
Transaction beginTransaction = session.beginTransaction();
Order order2 = session.get(order.getClass(), order.getOrder_id());
//提交事务
beginTransaction.commit();
//关闭会话
session.close();
return order2;
}
}
HibernateUtils.java代码

package com.hibernate.util;

import java.io.Serializable;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.hibernate.entity.Student;
import com.hibernate.entity.User;
import com.hibernate.entity.Worker;

public class HibernateUtils {

private static SessionFactory sessionFactory=null;
private static ThreadLocal<Session> local=new ThreadLocal<>(); 
static {
	/*
	 * hibernate使用七步走:
	 * 		1、对hibernate.cfg.xml建模
	 * 		2、通过建模所得到的config文件类,获取所配置的sessionfactory
	 * 		3、获取session会话
	 * 		4、开启事务
	 * 		5、操作数据库
	 * 		6、提交事务
	 * 		7、关闭session会话
	 */
	
	// 由于hibernate已经帮我们封装好了, 建模这一步就不用那么麻烦了, 直接调用它的就行:
	Configuration configure = new Configuration().configure("hibernate.cfg.xml");
	sessionFactory = configure.buildSessionFactory();
	// 这里的session会话可以理解为数据库的connection
	
}
    //得到session会话
public static Session getSession() {
	Session session = local.get();  
	if(session==null) {
		session = sessionFactory.openSession();
		local.set(session);   
	}
	return session;
}

}

使用junit进行测试:

package com.hibernate.dao;

import static org.junit.Assert.*;

import org.junit.Test;

import com.hibernate.entity.Order;

public class OrderDaoTest {

private OrderDao od=new OrderDao();
@Test
public void testGet() {
            //参数
	Order order=new Order();
	order.setOrder_id(1);
            //调用方法
	Order order2 = od.get(order);
            //打印数据结果
	System.out.println(order2.toString());
	Set<OrderItem> orderItems = order2.getOrderItems();
	orderItems.stream().map(OrderItem::toString).forEach(System.out::println);
}

}

如果直接测试是会报错的,

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.hibernate.entity.Order.orderItems, could not initialize proxy - no Session

由于hibernate采用的是懒加载:当你使用除主键列以外的其他属性时,hibernate才会去数据库进行查询,由于之前我们在dao方法中将session关闭掉了,所以会报错。

解决办法:

将一下两行代码加入到dao方法中即可(下面的代码是设置直接加载那些属性,并不一定要按照我这样设置,可依情况而定):

Hibernate.initialize(order2); order2不使用懒加载,直接直接加载到对象order2中
Hibernate.initialize(order2.getOrderItems()); order2的订单项不使用懒加载,直接直接加载到对象order2中

修改后的dao:

package com.hibernate.dao;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.hibernate.entity.Order;
import com.hibernate.util.HibernateUtils;

public class OrderDao {
/**
* 查询订单时,对应的订单项也会一同查询出来。
* @param order
* @return
*/
public Order get(Order order) {
//HibernateUtils为自己写的一个工具类,得到会话
Session session = HibernateUtils.getSession();
//开启事务。
Transaction beginTransaction = session.beginTransaction();
Order order2 = session.get(order.getClass(), order.getOrder_id());
Hibernate.initialize(order2);
Hibernate.initialize(order2.getOrderItems());
//提交事务
beginTransaction.commit();
//关闭会话
session.close();
return order2;
}
}


最终输出结果
hibernate中一对多双向关联的记录