Hibernate关联关系(一对多)
1. 什么是关联(association)1.1 关联指的是类之间的引用关系。如果类A与类B关联那么被引用的类B将被定义为类A的属性。例如t_hibernate_order t_hibernate_order_item 一个订单对应多个订单项 class Order{ private ListOrderItem 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 ListOrderItem orderItems new ArrayListOrderItem(); 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 ListOrderItem getOrderItems() { return orderItems; } public void setOrderItems(ListOrderItem orderItems) { this.orderItems orderItems; } Override public String toString() { return Order [orderId orderId , orderNo orderNo , orderItems orderItems ]; }}OrderItem.javapackage 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 version1.0 encodingUTF-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 namecom.cjq.three.entity.Order tablet_hibernate_order id nameorderId typejava.lang.Integer columnorder_id generator classincrement / /id property nameorderNo typejava.lang.String columnorder_no /property !-- bag标签 name:当前要映射的类的关联属性 cascade:维护关联关系 inverse:决定由谁来维护关联关系 key标签 column:表的外键对应的列段 one-to-many class:关联属性对应的类的全路径名 -- bag nameorderItems inversetrue cascadesave-update key columnoid/key one-to-many classcom.cjq.three.entity.OrderItem/ /bag /class /hibernate-mappingOrderItem.hbm.xml?xml version1.0 encodingUTF-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 namecom.cjq.three.entity.OrderItem tablet_hibernate_order_item id nameorderItemId typejava.lang.Integer columnorder_item_id generator classincrement / /id property nameproductId typejava.lang.Integer columnproduct_id /property property namequantity typejava.lang.Integer columnquantity /property property nameoid typejava.lang.Integer columnoid /property !-- many-to-one 多对一的配置(因为多个订单项对应一个订单 name:指的是当前所要映射的类的关联com.cjq.three.entity.OrderItem属性order class:指的是关联属性的类别全路径名 column:填的是从表外键(主表是一的一方从表是多的一方) -- many-to-one nameorder classcom.cjq.three.entity.Order columnoid/many-to-one /class /hibernate-mapping(3).dao层DemoDao.javapackage 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 { /** * 为了测试关系型映射文件配置准确 讲解insertfalseupdatefalse的用途 * * 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 ListOrder getOrderList() { Session session SessionFactoryUtils.openSession(); Transaction transaction session.beginTransaction(); ListOrder 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.javapackage 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 resourcecom/cjq/three/entity/Order.hbm.xml / mapping resourcecom/cjq/three/entity/OrderItem.hbm.xml /运行有如下错误这里的oid列段有两个进行维护重复了解决方法在OrderItem.hbm.xml中加入列段维护property nameoid typejava.lang.Integer columnoid insertfalse updatefalse /property结果如下测试增加订单项Test public void testAddOrderItem() { OrderItem oinew OrderItem(); oi.setProductId(66); oi.setQuantity(66); Order ordernew Order(); order.setOrderId(11); oi.setOrder(order); demoDao.addOrderItem(oi); }懒加载问题代码如下Test public void testGetOrder() { Order ordernew 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() { ListOrder orderlistnew 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 InitChildren0;//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.javaTest public void testGetOrder() { Order ordernew 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?结果如下