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 + "]";
}
}
订单实体的映射配置文件
<!-- 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 + "]";
}
}
订单项实体的映射配置文件
<!-- 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;
}
}
最终输出结果