Hibernate关联关系(一对多)

📅 2026/7/28 15:51:08 👁️ 阅读次数 📝 编程学习
Hibernate关联关系(一对多)

1. 什么是关联(association)

1.1 关联指的是类之间的引用关系。如果类A与类B关联,那么被引用的类B将被定义为类A的属性。
例如:

t_hibernate_order t_hibernate_order_item 一个订单对应多个订单项 class Order{ private List<OrderItem> orderItems; } class OrderItem{ private Order order; } class B{ private String name; } public class A{ private B b = new B; public A(){} }

1.2 关联的分类:关联可以分为一对一、一对多/多对一、多对多关联
关联是有方向的

以订单表、订单项表为示例:
(1).创建两个实体类:

Order.java:

package com.cjq.three.entity; import java.util.ArrayList; import java.util.List;public class Order { private Integer orderId; private String orderNo; private List<OrderItem> orderItems = new ArrayList<OrderItem>(); 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; } public List<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(List<OrderItem> orderItems) { this.orderItems = orderItems; } @Override public String toString() { return "Order [orderId=" + orderId + ", orderNo=" + orderNo + ", orderItems=" + orderItems + "]"; }}

OrderItem.java:

package com.cjq.three.entity; public class OrderItem { private Integer orderItemId; private Integer productId; private Integer quantity; private Integer oid; private 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; } public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } @Override public String toString() { return "OrderItem [orderItemId=" + orderItemId + ", productId=" + productId + ", quantity=" + quantity + ", oid=" + oid + "]"; }}

(2).再配置映射文件:
Order.hbm.xml

<?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.cjq.three.entity.Order" table="t_hibernate_order"> <id name="orderId" type="java.lang.Integer" column="order_id"> <generator class="increment" /> </id> <property name="orderNo" type="java.lang.String" column="order_no"> </property> <!-- bag标签: name:当前要映射的类的关联属性 cascade:维护关联关系 inverse:决定由谁来维护关联关系 key标签 column:表的外键对应的列段 one-to-many: class:关联属性对应的类的全路径名 --> <bag name="orderItems" inverse="true" cascade="save-update"> <key column="oid"></key> <one-to-many class="com.cjq.three.entity.OrderItem"/> </bag> </class> </hibernate-mapping>

OrderItem.hbm.xml

<?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.cjq.three.entity.OrderItem" table="t_hibernate_order_item"> <id name="orderItemId" type="java.lang.Integer" column="order_item_id"> <generator class="increment" /> </id> <property name="productId" 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> <!-- many-to-one 多对一的配置(因为多个订单项对应一个订单) name:指的是当前所要映射的类的关联com.cjq.three.entity.OrderItem属性order class:指的是关联属性的类别(全路径名) column:填的是从表外键(主表是一的一方:从表是多的一方) --> <many-to-one name="order" class="com.cjq.three.entity.Order" column="oid"></many-to-one> </class> </hibernate-mapping>

(3).dao层
DemoDao.java

package com.cjq.three.dao; import java.util.List;import org.hibernate.Session; import org.hibernate.Transaction;import com.cjq.three.entity.Order; import com.cjq.three.entity.OrderItem; import com.cjq.two.util.SessionFactoryUtils;public class DemoDao { /** * 为了测试关系型映射文件配置准确 讲解insert=false,update=false的用途 * * @param order * @return */ public Integer addOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer oid = (Integer) session.save(order); transaction.commit(); session.close(); return oid; } public Integer addOrderItem(OrderItem orderItem) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer otid = (Integer) session.save(orderItem); transaction.commit(); session.close(); return otid; } /** * 为了讲解懒加载的问题(hibernate3.0后所有查询方式默认采用的是懒加载方式) 1、查单个时存在问题,代理对象已经关闭 * 2、查多个存在问题,有性能的问题 * * @param order * @return */ public Order getOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); // if(o != null && new Integer(1).equals(order.getInitChildren())) { // Hibernate.initialize(o.getOrderItems()); //// System.out.println(o.getOrderItems()); // } transaction.commit(); session.close(); return o; } public List<Order> getOrderList() { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); List<Order> list = session.createQuery("from Order").list(); transaction.commit(); session.close(); return list; } /** * z主表的数据不能随便删除,得先删除从表中对应信息,才能删除主表的信息。 * * @param order */ public void delOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Order order2 = session.get(Order.class, order.getOrderId()); for (OrderItem oi : order2.getOrderItems()) { session.delete(oi); } session.delete(order2); // session.delete(order); transaction.commit(); session.close(); } }

DemoDaoTest.java

package com.cjq.three.dao; import static org.junit.Assert.*;import org.junit.Test;import com.cjq.three.entity.Order; import com.cjq.three.entity.OrderItem;public class DemoDaoTest { private DemoDao demoDao = new DemoDao(); @Test public void testAddOrder() { Order order = new Order(); order.setOrderNo("T237购物"); for (int i = 0; i < 6; i++) { OrderItem oi = new OrderItem(); oi.setProductId(10 + i); oi.setQuantity(20 + i); // 以前做法 demoDao.addOrderItem(oi); // 绑定订单项和订单的关系 order.getOrderItems().add(oi); oi.setOrder(order); } // 以前做法 demoDao.addOrder(order); demoDao.addOrder(order); } @Test public void testAddOrderItem() { } @Test public void testGetOrder() { } @Test public void testGetOrderList() { } @Test public void testDelOrder() { }}

(4).在核心文件hibernate.cfg.xml中配置:

<!-- 讲解一对多 --> <mapping resource="com/cjq/three/entity/Order.hbm.xml" /> <mapping resource="com/cjq/three/entity/OrderItem.hbm.xml" />

运行:
有如下错误:

这里的oid列段有两个进行维护,重复了!
解决方法:
在OrderItem.hbm.xml中加入列段维护:

<property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"> </property>

结果如下:


测试增加订单项:

@Test public void testAddOrderItem() { OrderItem oi=new OrderItem(); oi.setProductId(66); oi.setQuantity(66); Order order=new Order(); order.setOrderId(11); oi.setOrder(order); demoDao.addOrderItem(oi); }

懒加载问题:

代码如下:

@Test public void testGetOrder() { Order order=new Order(); order.setOrderId(11); Order o = demoDao.getOrder(order); //得到11这个订单 System.out.println(o.getOrderNo()); //得到11所有的订单项 System.out.println(o.getOrderItems()); }

出现如下错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.cjq.three.entity.Order.orderItems, could not initialize proxy - no Session at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:589) at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:208) at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:568) at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:139) at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:511) at java.lang.String.valueOf(Unknown Source) at java.io.PrintStream.println(Unknown Source) at com.cjq.three.dao.DemoDaoTest.testGetOrder(DemoDaoTest.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)

两种解决方案:
1.在配置文件Order.hbm.xml中加载lazy(不推荐)
再测试方法:

在这里插入代码片
@Test public void testGetOrderList() { List<Order> orderlist=new DemoDao().getOrderList(); for (Order order : orderlist) { System.out.println(order.getOrderNo()); System.out.println(order.getOrderItems().size()); } }

结果如下:

Hibernate: select order0_.order_id as order_id1_0_, order0_.order_no as order_no2_0_ from t_hibernate_order order0_ Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? P1 0 P7 8 P101 6 P20 6 T226 3 T237购物 6

查询多少次sql语句就进行多次(多少条数据就进行多少次+1)。导致性能变差。
2.第二种(先将之前的lazy属性清除):
O在rder.java加入如下代码:

private Integer InitChildren=0;//0代表默认。默认代表懒加载.1代表强制加载 public Integer getInitChildren() { return InitChildren; } public void setInitChildren(Integer initChildren) { InitChildren = initChildren; }

更改DenoDao.java方法:

/** * 为了讲解懒加载的问题(hibernate3.0后所有查询方式默认采用的是懒加载方式) * 1、查单个时存在问题,代理对象已经关闭 * 2、查多个存在问题,有性能的问题 * @param order * @return */ public Order getOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); //当 order.getInitChildren() 为 1 时 强制加载o.getOrderItems() //这样既兼顾了性能,也能成功加载o.getOrderItems() if(o != null && new Integer(1).equals(order.getInitChildren())) { Hibernate.initialize(o.getOrderItems()); // System.out.println(o.getOrderItems()); } transaction.commit(); session.close(); return o; }

DemoDaoTest.java:

@Test public void testGetOrder() { Order order=new Order(); order.setOrderId(11); order.setInitChildren(1); Order o = demoDao.getOrder(order); System.out.println(o.getOrderNo()); System.out.println(o.getOrderItems().size()); }

结果如下:

3.测试删除方法:

/** * 删除 */ @Test public void testDelOrder() { Order order = new Order(); order.setOrderId(11); this.DemoDao.delOrder(order); }

Console控制台显示:

Hibernate: select order0_.order_id as order_id1_0_0_, order0_.order_no as order_no2_0_0_ from t_hibernate_order order0_ where order0_.order_id=? Hibernate: select orderitems0_.oid as oid4_1_0_, orderitems0_.order_item_id as order_it1_1_0_, orderitems0_.order_item_id as order_it1_1_1_, orderitems0_.product_id as product_2_1_1_, orderitems0_.quantity as quantity3_1_1_, orderitems0_.oid as oid4_1_1_ from t_hibernate_order_item orderitems0_ where orderitems0_.oid=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order_item where order_item_id=? Hibernate: delete from t_hibernate_order where order_id=?

结果如下: