一对多双向关联
数据库脚本建表:
-- 订单表(主表)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"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping> <class name="com.hibernate.entity.Order" table="t_hibernate_order"> <id name="order_id" type="java.lang.Integer" column="order_id"> <generator class="increment"></generator> </id> <property name="order_no" type="java.lang.String" column="order_no"></property> <!-- 上面就不介绍了,基本属性的配置 --> <!-- name属性为Order实体中订单项的属性名 --> <set name="orderItems"> <!-- column 为订单项中外键的属性名 --> <key column="oid"></key> <!-- class为订单项的全限定名 --> <one-to-many class="com.hibernate.entity.OrderItem"/> </set> </class></hibernate-mapping>
订单项
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"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping> <class name="com.hibernate.entity.OrderItem" table="t_hibernate_order_item"> <id name="order_item_id" type="java.lang.Integer" column="order_item_id"> <generator class="increment"></generator> </id> <property name="product_id" 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"></property> <!-- 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-mapping>
将订单于订单项的配置文件配置到hibernate的核心配置文件中:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <!-- 配置数据源信息 --> <property name="connection.username">root</property> <property name="connection.password">123</property> <property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 配置sql语句生成的规则,配置数据库方言 --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 配置本地事务 --> <property name="hibernate.current_session_context_class">thread</property> <!-- 配置开发调试所用的配置show_sql,format_sql --> <property name="show_sql">true</property> <property name="format_sql">true</property> <!-- 配置映射文件 --> <mapping resource="com/hibernate/entity/Order.hbm.xml"/> <mapping resource="com/hibernate/entity/OrderItem.hbm.xml"/> </session-factory></hibernate-configuration>
编写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; }}
最终输出结果: