hibernate的关联、一对多(4)

本文深入解析对象关系映射(ORM)中的关联关系,包括一对一、一对多和多对多关联,探讨了关联的方向性及其在数据库设计中的体现,如外键的使用。详细介绍了Hibernate框架下如何实现这些关联关系,涉及的属性如cascade、inverse、outer-join、lazy的解释,以及它们在实体类间的应用,特别关注一对多双向关联的建立。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 什么是关联(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. 如何将多方映射成一个有序的集合

    核心
    订单表、订单项

级联新增
外键处理的三种方式
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);
	}
	}
内容概要:本文档详细介绍了一个基于MATLAB实现的跨尺度注意力机制(CSA)结合Transformer编码器的变量时间序列预测项目。项目旨在精准捕捉尺度时间序列特征,提升变量时间序列的预测性能,降低模型计算复杂度与训练时间,增强模型的解释性和可视化能力。通过跨尺度注意力机制,模型可以同时捕获局部细节和全局趋势,显著提升预测精度和泛化能力。文档还探讨了项目面临的挑战,如尺度特征融合、变量复杂依赖关系、计算资源瓶颈等问题,并提出了相应的解决方案。此外,项目模型架构包括跨尺度注意力机制模块、Transformer编码器层和输出预测层,文档最后提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,尤其是熟悉MATLAB和深度学习的科研人员、工程师和研究生。 使用场景及目标:①需要处理变量、尺度时间序列数据的研究和应用场景,如金融市场分析、气象预测、工业设备监控、交通流量预测等;②希望深入了解跨尺度注意力机制和Transformer编码器在时间序列预测中的应用;③希望通过MATLAB实现高效的变量时间序列预测模型,提升预测精度和模型解释性。 其他说明:此项目不仅提供了一种新的技术路径来处理复杂的时间序列数据,还推动了领域变量时间序列应用的创新。文档中的代码示例和详细的模型描述有助于读者快速理解和复现该项目,促进学术和技术交流。建议读者在实践中结合自己的数据集进行调试和优化,以达到最佳的预测效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值