Hibernate 关联关系(一对多)
Hibernate 关联关系(一对多)
1. 什么是关联(association)
1.1 关联指的是类之间的引用关系。如果类A与类B关联,那么被引用的类B将被定义为类A的属性。例如:
class B{
private String name;
private List<A> bs = new arraylist();
}
public class A{
private B b = new B;
public A(){
}
}
hibernate:orm框架、以面向对象的思想操作数据库
1.2 关联的分类:关联可以分为一对一、一对多/多对一、多对多关联
关联是有方向的
案列:
导入映射文件Order.hbm.xml和OrderItem.hbm.xml
Order.hbm.xm
进行关联关系的维护一对多的关系
OrderItem.hbm.xml
进行关联关系的维护 一对多的关系
hibernate.cfg.xml(核心配置文件)添加映射文件OrderItem.hbm.xml和Order.hbm.xm
对应映射文件的实体类
Order.hbm.xml
Order
1 package com.MavenHibernate.three.entity; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class Order { 7 8 private Integer orderId; 9 private String orderNo; 10 private List<OrderItem> orderItems = new ArrayList<>(); 11 12 public List<OrderItem> getOrderItems() { 13 return orderItems; 14 } 15 16 public void setOrderItems(List<OrderItem> orderItems) { 17 this.orderItems = orderItems; 18 } 19 20 public List<OrderItem> getOrderItem() { 21 return orderItems; 22 } 23 24 public void setOrderItem(List<OrderItem> orderItem) { 25 this.orderItems = orderItem; 26 } 27 @Override 28 public String toString() { 29 return "Order [orderId=" + orderId + ", orderNo=" + orderNo + ", orderItem=" + orderItems + "]"; 30 } 31 public Integer getOrderId() { 32 return orderId; 33 } 34 public void setOrderId(Integer orderId) { 35 this.orderId = orderId; 36 } 37 public String getOrderNo() { 38 return orderNo; 39 } 40 public void setOrderNo(String orderNo) { 41 this.orderNo = orderNo; 42 } 43 public Order(Integer orderId, String orderNo) { 44 super(); 45 this.orderId = orderId; 46 this.orderNo = orderNo; 47 } 48 public Order() { 49 super(); 50 } 51 52 }
OrderItem.hbm.xml
OrderItem
1 package com.MavenHibernate.three.entity; 2 3 public class OrderItem { 4 5 private Integer orderItemId; 6 private Integer productId; 7 private Integer quantity; 8 private Integer oid; 9 private Order order; 10 11 public Order getOrder() { 12 return order; 13 } 14 public void setOrder(Order order) { 15 this.order = order; 16 } 17 @Override 18 public String toString() { 19 return "OrderItem [orderItemId=" + orderItemId + ", productId=" + productId + ", quantity=" + quantity 20 + ", oid=" + oid + ", order=" + order + "]"; 21 } 22 public Integer getOrderItemId() { 23 return orderItemId; 24 } 25 public void setOrderItemId(Integer orderItemId) { 26 this.orderItemId = orderItemId; 27 } 28 public Integer getProductId() { 29 return productId; 30 } 31 public void setProductId(Integer productId) { 32 this.productId = productId; 33 } 34 public Integer getQuantity() { 35 return quantity; 36 } 37 public void setQuantity(Integer quantity) { 38 this.quantity = quantity; 39 } 40 public Integer getOid() { 41 return oid; 42 } 43 public void setOid(Integer oid) { 44 this.oid = oid; 45 } 46 public OrderItem(Integer orderItemId, Integer productId, Integer quantity, Integer oid) { 47 super(); 48 this.orderItemId = orderItemId; 49 this.productId = productId; 50 this.quantity = quantity; 51 this.oid = oid; 52 } 53 public OrderItem() { 54 super(); 55 } 56 57 }
测试:
DemoDao
1 package com.MavenHibernate.three.Dao; 2 3 import java.util.List; 4 5 import org.hibernate.Session; 6 import org.hibernate.Transaction; 7 8 import com.MavenHibernate.three.entity.Order; 9 import com.MavenHibernate.three.entity.OrderItem; 10 import com.MavenHibernate.two.util.SessionFactoryUtils; 11 12 13 14 public class DemoDao { 15 /** 16 * 为了测试关系型映射文件配置准确 17 * 讲解insert=false,update=false的用途 18 * @param order 19 * @return 20 */ 21 public Integer addOrder(Order order) { 22 Session session = SessionFactoryUtils.openSession(); 23 Transaction transaction = session.beginTransaction(); 24 Integer oid = (Integer)session.save(order); 25 transaction.commit(); 26 session.close(); 27 return oid; 28 } 29 30 public Integer addOrderItem(OrderItem orderItem) { 31 Session session = SessionFactoryUtils.openSession(); 32 Transaction transaction = session.beginTransaction(); 33 Integer otid = (Integer)session.save(orderItem); 34 transaction.commit(); 35 session.close(); 36 return otid; 37 } 38 39 40 41 /** 42 * 为了讲解懒加载的问题(hibernate3.0后所有查询方式默认采用的是懒加载方式) 43 * 1、查单个时存在问题,代理对象已经关闭 44 * 2、查多个存在问题,有性能的问题 45 * @param order 46 * @return 47 */ 48 public Order getOrder(Order order) { 49 Session session = SessionFactoryUtils.openSession(); 50 Transaction transaction = session.beginTransaction(); 51 Order o = session.get(Order.class, order.getOrderId()); 52 // if(o != null && new Integer(1).equals(order.getInitChildren())) { 53 // Hibernate.initialize(o.getOrderItems()); 54 //// System.out.println(o.getOrderItems()); 55 // } 56 transaction.commit(); 57 session.close(); 58 return o; 59 } 60 61 public List<Order> getOrderList() { 62 Session session = SessionFactoryUtils.openSession(); 63 Transaction transaction = session.beginTransaction(); 64 List<Order> list = session.createQuery("from Order").list(); 65 transaction.commit(); 66 session.close(); 67 return list; 68 } 69 70 /** 71 * z主表的数据不能随便删除,得先删除从表中对应信息,才能删除主表的信息。 72 * @param order 73 */ 74 public void delOrder(Order order) { 75 Session session = SessionFactoryUtils.openSession(); 76 Transaction transaction = session.beginTransaction(); 77 Order order2 = session.get(Order.class, order.getOrderId()); 78 for (OrderItem oi : order2.getOrderItems()) { 79 session.delete(oi); 80 } 81 session.delete(order2); 82 // session.delete(order); 83 transaction.commit(); 84 session.close(); 85 } 86 }
利用junit进行DemoDao测试
DemoDaoTest
1 package com.MavenHibernate.three.Dao; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.Before; 6 import org.junit.Test; 7 8 import com.MavenHibernate.three.entity.Order; 9 import com.MavenHibernate.three.entity.OrderItem; 10 11 public class DemoDaoTest { 12 13 private DemoDao demoDao=new DemoDao(); 14 15 @Before 16 public void setUp() throws Exception { 17 } 18 19 @Test 20 public void testAddOrder() { 21 Order order = new Order(); 22 order.setOrderNo("226"); 23 OrderItem oi=null; 24 for (int i = 0; i < 3; i++) { 25 oi = new OrderItem(); 26 oi.setProductId(10+i); 27 oi.setQuantity(20+i); 28 oi.setOrder(order); 29 order.getOrderItems().add(oi); 30 31 } 32 demoDao.addOrder(order); 33 } 34 35 //订单项 36 @Test 37 public void testAddOrderItem() { 38 Order order = new Order(); 39 order.setOrderId(5); 40 OrderItem oi=null; 41 for (int i = 0; i < 3; i++) { 42 oi = new OrderItem(); 43 oi.setProductId(10+i); 44 oi.setQuantity(20+i); 45 oi.setOrder(order); 46 order.getOrderItems().add(oi); 47 demoDao.addOrderItem(oi); 48 49 } 50 } 51 52 53 54 }
结果:
订单项
2.懒加载
DemoDaoTest
运行时控制台会报一个这样的错误:
处理方式:(第一种)
在对应实体映射文件中的关联关系的维护中添加 lazy="false"
处理方式:(第二种)
在一对多的实体类中添加属性是否打开懒加载
在order实体类中
DemoDao中的懒加载方法
DemoDaoTest
1 package com.MavenHibernate.three.Dao; 2 3 import static org.junit.Assert.*; 4 5 import java.util.List; 6 7 import org.junit.Before; 8 import org.junit.Test; 9 10 import com.MavenHibernate.three.entity.Order; 11 import com.MavenHibernate.three.entity.OrderItem; 12 13 public class DemoDaoTest { 14 15 private DemoDao demoDao=new DemoDao(); 16 17 18 public void setUp() throws Exception { 19 } 20 21 @Test 22 public void testAddOrder() { 23 Order order = new Order(); 24 order.setOrderNo("226"); 25 OrderItem oi=null; 26 for (int i = 0; i < 3; i++) { 27 oi = new OrderItem(); 28 oi.setProductId(10+i); 29 oi.setQuantity(20+i); 30 oi.setOrder(order); 31 order.getOrderItems().add(oi); 32 33 } 34 demoDao.addOrder(order); 35 } 36 37 //订单项 38 @Test 39 public void testAddOrderItem() { 40 Order order = new Order(); 41 order.setOrderId(5); 42 OrderItem oi=null; 43 for (int i = 0; i < 3; i++) { 44 oi = new OrderItem(); 45 oi.setProductId(10+i); 46 oi.setQuantity(20+i); 47 oi.setOrder(order); 48 order.getOrderItems().add(oi); 49 demoDao.addOrderItem(oi); 50 51 } 52 } 53 54 /** 55 * 关于懒加载的问题 56 * hibernate3之后出现的 57 * failed to lazily initialize a collection of role: 58 * com.MavenHibernate.three.entity.Order.orderItems, could not initialize proxy - no Session 59 * * orderNo数据来源于t_hibernate_order表 60 * orderItems数据来源于t_hibernate_order_item表 61 * 62 * 因为两表有关联关系所以不可以分开查询, 63 * 而hibernate默认的策略是不查询关联关系对应关联表数据的 64 * 65 * 处理方式:(第一种) 66 * 在对应实体映射文件中的关联关系的维护中添加 lazy="false" 67 * 如:<bag lazy="false" name="orderItems" cascade="save-update" inverse="true"> 68 */ 69 70 71 @Test 72 public void testGetOrder() { 73 Order order = new Order(); 74 order.setOrderId(10); 75 //关闭懒加载 76 order.setInitChildren(0); 77 Order o = this.demoDao.getOrder(order); 78 System.out.println(o.getOrderNo()); 79 System.out.println(o.getOrderItems()); 80 } 81 82 /** 83 * 查询多个 84 * 在查询单个中懒加载问题的解决方案 85 * 会导致在查询多个的时候sql语句也会增多, 86 * 当查询数据过多的时候导致代码性能变低 87 * 88 * 总:如果将懒加载的功能关闭,即:lazy=false, 89 * 那么在查询多条订单数据的情况下是非常影响性能的 90 * 91 * 查单个需要关闭懒加载 目的是需要加载出关联表的数据 92 * 查多个不能关闭懒加载 加载关联表的数据的查询次数过多 93 * 94 * 处理方式:(第二种) 95 * 在一对多的实体类中添加属性是否打开懒加载 96 * 97 */ 98 @Test 99 public void testGetOrderList() { 100 List<Order> orderList = this.demoDao.getOrderList(); 101 for (Order order : orderList) { 102 System.out.println(order.getOrderNo()); 103 // System.out.println(order.getOrderItems()); 104 } 105 } 106 /** 107 * 删除订单,关联关系同时删除 108 */ 109 @Test 110 public void testDelOrder() { 111 Order order = new Order(); 112 order.setOrderId(10); 113 this.demoDao.delOrder(order); 114 } 115 116 }