-
什么是关联(association)
1.1 关联指的是类之间的引用关系。如果类A与类B关联,那么被引用的类B将被定义为类A的属性。例如:public class A{ private B b = new B(); public A(){} }
1.2 关联的分类:关联可以分为一对一、一对多/多对一、多对多关联
关联是有方向的
一个订单表对应多个订单项,多个订单项对应一个订单表
订单表、订单项表
select * from t_order t,t_orderItem m where t.oid = m.oid
and .....
class Order{
private STIRNG OID;
...
private Set<OrderItem> OrderItems;
}
session.get(Order.class,1)
#关键点都在数据库中的外键上面,请好好理解下面这二句SQL和一对多及多对一的关系
#select * from Orders where cid=? //这条SQL返回客户对应的0-n个订单
#select * from Customers where customerId=? //这条SQL返回订单对应的1个客户
#通过这二条SQL不难看出,外键在这里有二个用途:查找客户的订单,查找订单对应的客户
2. 案例:如何建立客户和订单一对多双向关联
2.1 先不建立客户和订单的关联关系,定义实体及映射文件,单独执行保存操作
2.2 建立客户到订单的一对多关联关系
2.3 建立订单到客户的多对一关联关系
<many-to-one name="customer" class="entity.Customer" column="cid">
<!--1.注释 2.只读-->
<property name="cid" type="java.lang.Integer" column="cid" insert="false" update="false">
</property>
2.4 注意:在Hibernate当中定义实体对象的集合属性时,只能使用接口而不能使用类
#insert属性设置中主控方概念理解:
3. 以客户和订单的一对多双向关联为例,讲解Set元素中的cascade|inverse|outter-join|lazy属性作用
3.1 lazy:默认值为true,true延迟加载,false立即加载(一般设置为true,不使用立即加载,因为影响查询性能)
3.2 outter-join:默认值为false,true使用左外联接查询关联的(但一般不用,因为当我们把该属性设置为true时,所有的查询语句都会默认左外联,那样性能不高)
3.3 inverse:默认值为false,true表示将对方设置为主控方(一对多双向关联中一般将多方设置为主控方,这样可以减少SQL语句的数量,减少多余的操作)
3.4 cascade:用来控制如何操作关联的持久化对象的
3.4.1 none:保存,更新或删除当前对象时,忽略其它关联的对象
3.4.2 save-update:保存、更新时级联保存所有的临时对象,并且级联更新关联的游离对象
3.4.3 delete:通过session的delete方法删除当前对象,级联删除关联的对象
3.4.4 all:等于save-update操作+delete操作
小结:
多方的CRUD与没有建立关联关系之前的操作一致
一方的CRUD与没有建立关联关系之前的操作有变化
D:删除一方之前先删除多方
C:级联操作
R:代码控制多方
-
案例:菜单对象的一对多双向自关联
-
如何将多方映射成一个有序的集合
核心
订单表、订单项
级联新增
外键处理的三种方式
1、删除从表对应的实体类中的外键属性
2、在配置的xml中外键属性上添加 insert=false,update=false的设置。
3、在配置的xml中的manyToOne标签中添加insert=false,update=false的设置。
级联新增 casecade=save-update 介绍
级联查询
配置文件介绍以及后台sql的形成过程
级联查询时的问题
Lazy=true介绍 查单个时存在问题
Lazy=false介绍 查所有时存在问题
解决方案:通过字段控制,强制加载。Hibernate.initialize()
普通删除
Order
Add 讲外键的处理
Get/list order.getOrderItems.size讲懒加载的处理,sql形成过程
Del 将关系的处理中的删除
代码:
2个实体类:
订单表:
package com.four.entity;
import java.util.HashSet;
import java.util.Set;
public class Order {
private Integer orderId;
private String orderNo;
//定义一对多的关系时 一定需要采用接口方式,不许使用实现类①
private Set<OrderItem> orderItems=new HashSet<OrderItem>();//一对多的关系
private Integer initOrderItems =0; //0代表懒加载 1代表立即加载
public Integer getInitOrderItems() {
return initOrderItems;
}
public void setInitOrderItems(Integer initOrderItems) {
this.initOrderItems = initOrderItems;
}
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
this.orderItems = orderItems;
}
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;
}
}
订单项表:
package com.four.entity;
public class OrderItem {
private Integer orderItemId;
private Integer productId;
private Integer quantity;
private Integer oid;
private Order order;
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.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;
}
}
配置:
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 table="t_hibernate_order" name="com.four.entity.Order">
<!--
session.getOrder
->select *from t_hibernate_order where order_id =?(以7为例)
7 P7
Order order = Class.forName("com.four.entity.Order").newInstanse(): 反射实例化
order.setOrderId(7);
order.setOrderId(P7);
通过外键:one-to-many 找到orderItem.hbm.xml文件
形成了一个sql语句 (建模)select *from t_hibernate_order_item where oid(外键)=?(当前主键 7)
查出来一个集合
28 11 11 7
29 11 11 7 (配置文件介绍以及后台sql的形成过程)
30 11 11 7
...
通过反射得到含有数据库查出来的值得对象集合 EntityBaseDao的处理(建模的一个类)
orderItems=List<OrderItem>
order.setOrderItems(orderItems);
-->
<id name="orderId" type="java.lang.Integer" column="order_id">
<generator class="increment"></generator>
</id>
<property name="orderNo" type="java.lang.String" column="order_no"></property>
<!--
cascade:用来配置维护实体类之间的关系所用
inverse:关系交由反方控制 =true 就是交给反方,false就是自己控制
反方是谁?现在我们配置这个表是Order订单,那么反方就是订单项
跟它有关系的另外一方,就是反方 关系交给订单项来维护
-->
<!--lazy 默认是懒加载 true false就是立即加载 懒加载多少条数据,查询多少条,列50条,查询51次,太占内存和性能。所以定义一个initOrderItems--> <!-- lazy="false" -->
<!-- 级联保存和修改 改为级联删除,但是有问题。等多对多的时候在讲 -->
<set name="orderItems" cascade="save-update" inverse="true">
<!-- 这里一定填外键 -->
<key column="oid"></key>
<!-- 一对多 对应多个订单项 -->
<one-to-many class="com.four.entity.OrderItem"></one-to-many>
</set>
</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 table="t_hibernate_order_item" name="com.four.entity.OrderItem">
<id name="orderItemId" type="java.lang.Integer" column="order_Item_id">
<generator class="increment"></generator>
</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" insert="false" update="false"></property>
<!-- 这张表,对应后台的那个字段 -->
<!-- 会报错 --><!-- 可以交给上面来维护,也可以交给下面维护 把上面的insert。。。。放到下面,上面的oid就可以操作数据库 -->
<many-to-one name="order" class="com.four.entity.Order" column="oid">
</many-to-one>
</class>
hibernate.cfg.xml(就是hibernate需要管理的数据库表对应的实体类映射文件,看我前面写的博客):
<!-- 一对多 -->
<mapping resource="com/four/entity/Order.hbm.xml"/>
<mapping resource="com/four/entity/OrderItem.hbm.xml"/>
Dao方法:
package com.four.dao;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.four.entity.Order;
import com.four.entity.OrderItem;
import com.tow.util.SessionFactoryUtil;
public class OrderDao {
//订单项增加
public Integer addOrderItem(OrderItem orderItem){
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Integer otid = (Integer) session.save(orderItem);
transaction.commit();
session.close();
return otid;
}
//订单增加
public Integer addOrder(Order order){
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Integer otid = (Integer) session.save(order);
transaction.commit();
session.close();
return otid;
}
//查询
public Order getOrder(Order order){
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Order o = session.get(Order.class, order.getOrderId());
//是否强制加载
if(o!=null && new Integer(1).equals(order.getInitOrderItems())){
Hibernate.initialize(o.getOrderItems());
}
transaction.commit();
session.close();
return o;
}
//查询
public List<Order> getOrderList(){
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
List list = session.createQuery("from Order").list();
transaction.commit();
session.close();
return list;
}
//普通删除
public void delOrder(Order order){
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
Order o = session.get(Order.class, order.getOrderId());
for (OrderItem ot : o.getOrderItems()) {
session.delete(ot);
}
session.delete(o);
transaction.commit();
session.close();
}
}
然后就是测试Junit:
package com.four.dao;
import static org.junit.Assert.*;
import java.util.List;
import org.hibernate.Session;
import org.junit.Test;
import com.four.entity.Order;
import com.four.entity.OrderItem;
public class OrderDaoTest {
private OrderDao orderDao=new OrderDao();
/**
*
* Caused by: org.hibernate.MappingException:
* Repeated column in mapping for entity:
* com.four.entity.OrderItem column: oid
* (should be mapped with insert="false" update="false")
* 同一字段被映射了两次
*/
@Test
public void testAddOrderItem() {
OrderItem orderItem=new OrderItem();
// orderItem.setOid(4);
orderItem.setProductId(89);
orderItem.setQuantity(78);
Order order=new Order();
order.setOrderId(4);
orderItem.setOrder(order);
this.orderDao.addOrderItem(orderItem);
}
/**
* 提交一个具有6个订单项的订单
* addOrder 1
* addOrderItem 6
*/
@Test
public void testAddOrder() {
Order order=new Order();
order.setOrderNo("P5");
OrderItem orderItem;
for (int i = 1; i < 7; i++) {
orderItem=new OrderItem();
orderItem.setProductId(i);
orderItem.setQuantity(i);
//双向关联
order.getOrderItems().add(orderItem);
orderItem.setOrder(order);
}
this.orderDao.addOrder(order);
}
/**
* org.hibernate.LazyInitializationException:
* failed to lazily initialize a collection of role:
* com.zking.four.entity.Order.orderItems,
* could not initialize proxy - no Session
* 懒加载
*/
@Test
public void testGetOrder() {
Order order=new Order();
order.setOrderId(5);
order.setInitOrderItems(1);
Order o = this.orderDao.getOrder(order);
System.out.println(o.getOrderNo());
System.out.println(o.getOrderItems().size());
//org.hibernate.collection.internal.PersistentSet PersistentSet看源码②
// System.out.println(o.getOrderItems().getClass().getName());
for (OrderItem ot : o.getOrderItems()) {
System.out.println(ot.getProductId());
}
}
@Test
public void testGetOrderList() {
List<Order> orderList = this.orderDao.getOrderList();
for (Order o : orderList) {
System.out.println(o.getOrderNo());
System.out.println(o.getOrderItems().size());
for (OrderItem ot : o.getOrderItems()) {
System.out.println(ot.getProductId());
}
}
}
/**
* 删不掉,2种方案:
* 1、把有关联的一起删除.
* 2、先查询出来,删除从表在删主表(太麻烦)
*/
@Test
public void testDelOrder() {
Order order=new Order();
order.setOrderId(4);
this.orderDao.delOrder(order);
}
}