一对多双向关联

数据库脚本建表:

-- 订单表(主表)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&amp;characterEncoding=UTF-8&amp;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;    }}

最终输出结果:

 

 

一对多双向关联