zoukankan      html  css  js  c++  java
  • Hibernate关系部分(二)

    简介

    今天学习之前闲扯一下。比如现在学hibernate为什么要学这么多,其实学习这回事,最重要的掌握学习方法,要有想法,掌握解决问题的一种思路。但作为学习者一定要勤奋,大量的练习,解决很多错误,后期做项目也就少些bug了,有一句话不是说代码量都是长期积累下来的嘛。主要了解hibernate关系部分,包括一对多单项、一对多双向、多对多双向、一对一

    一对多单项关系

    一对多的关联关系
    	Customer: 	id		name		Set<Order>
    	Order:		id		orderNum
    Order.hbm.xml
    <many-to-one name="customer" class="cn.itcast.oneToMany.Customer" cascade="save-update">
    	<column name="customer_id"></column>
    </many-to-one>
    
    多对一关联关系
    	Cusomter:	id		name
    	Order:		id		name		Customer
    Customer.hbm.xml配置文件中
    <set name="orders" cascade="save-update">
    
    级联
    	1. 在*.hbm.xml配置文件中配置<set name="students" cascade="save-update">
    	2. 代码中,必须建立关联	classes.setStudents(students);
    	3. 必须显示操作classes	session.save(classes)
    		显示操作	seession.save(classes)
    		隐式操作
    			当保存classes的时候,同时保存了student,而保存student操作是由hibernate内部来完成的。并不是程序员显示操作的,所以称为隐式操作
    隐式操作流程:
    在执行session.flush的时候,
    	 1、会检查hibernate一级缓存中所有的持久化状态的对象,来决定发出
    		   insert语句或者update语句
    	 2、会检查这些持久化对象中有没有关联对象,如果有,则再次去检查这些
    		|--持久化状态的对象中有没有设置级联,如果有
    			|--则检查关联对象是否是持久化状态的对象
    				|--如果是,则再次检查副本
    					|--如果不一样,则隐式发出update语句
    				|--关联对象不是持久化状态的对象
    					|--则发出insert语句
    	3、检查持久化对象是否有维护关系的权利,就是检查持久化对象对应的映射文件中的inverse属性是否为false/default,如果是该值,则会自动维护关系(会发出维护关系的update语句)

    一对多双向

    一、 一对多双向关系
    	1、一般情况下,一对多,多的一方维护关系,效率比较高
    	2、如果一的一方维护关系,会单独发出维护关系的update语句
    	3、在Customer.hbm.xml文件中
    	<set name="orders" table="j_order" cascade="save-update" inverse="false" order-by="id desc">
    		根据外键可以生成sql语句,因为设计到两张表,必须给定外键
    		<key>
    			<column name="cid"></column>
    		</key>
    		建立类与类之间的关系
    		<one-to-many class="cn.itcast.oneToManyDouble.Order"/>
    		指的是通过Customer建立Customer与Order之间的关系
    	</set>
    	4. 在Order.hbm.xml文件中
    		<many-to-one name="customer" class="cn.itcast.k_oneToManyDouble.Customer" cascade="save-update">
    					<column name="cid"></column>
    		</many-to-one>
    		指的是通过Order建立Customer与Order之间的关系
    	5、在客户端的编码中,发出的sql语句越少,效率越高。
    	6、如果是Order维护关系,不需要发出额外的更新关系的update语句,因为对学生的修改就直接包括了cid
    
    二、 定义接口类型属性
    	Hibernate要求在持久化类中定义集合属性时,必须把属性声明为接口类型,如Set、Map、List.声明为接口类型可提高持久化类的透明性,当hibernate调用setOrders()方法时,传递的参数是Hibernate自定义的实现该接口类的实例。如果定义成类(如HashSet)型,强迫hibernate把该类型的实例传给他。
            底层代码:
             Set<E> orders= PersistentSet
             class PersistentSet  implements java.util.Set
          通常在定义集合属性时,直接初始化为一个实现类的实例。
          private Set orders = new HashSet(0);
          可避免空指针异常
    三、 set中inverse属性
    	在hibernate中通过对 inverse 属性的值决定是由双向关联的哪一方来维护表和表之间的关系. inverse=false的为主动方,inverse=true 的为被动方, 由主动方负责维护关联关系
    	结论:
    		1.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,这可以提高性能。
    		2.在建立两个对象的关联时,应该同时修改关联两端的相应属性:
    		   customer.getOrders().add(order);
    		   order.setCustomer(customer);
    		这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改关联两端的对象的相应属性:
    		Customer.getOrders().remove(order);
    		Order.setCustomer(null);

    多对多双向

    1. 多对多描述是类与集合的关系
    	Course:	cid		name	Set<Student>
    	Student:sid		name	Set<Course>
    2. 映射文件中关联
    # course通过student_course表的cid与student关联
    	<set name="students" table="k_student_course" cascade="delete">
    		<key>
    			<column name="cid"></column>
    		</key>
    		<many-to-many class="cn.itcast.manyToMany.Student" column="sid"></many-to-many>
    	</set>
    
    # student通过student_course表的sid与course关联
    	<set name="courses" table="student_course" inverse="true">
    		<key>
    			<column name="sid"></column>
    		</key>
    		<many-to-many class="cn.itcast.manyToMany.Course" column="cid"></many-to-many>
    	</set>
    	
    总结:
    	1、一对多指的是类与集合的关系
    	2、多对一指的是类与类的关系
    	3、多对多指的是类与集合的关系
    	4、一对多的情况下,多的一方维护效率比较高
    	5、一对多的情况下,维护关系指的是对外键进行update操作(一的一方维护关系)
    		  多的一方维护关系,只是对多的一方进行所有的属性进行操作
    	6、多对多维护关系
    		  建立关系
    			   在第三张表中插入一行数据
    		  解除关系
    			   在第三张表中删除一行数据
    		  重新建立关系
    			   先删除后增加
    	7、因为多对多谁维护关系效率都一样,所以在映射文件中不需要写inverse属性
    	8、一般情况下一对多,在一的一方inverse属性设置为"true"

    检索策略

    1. 延迟加载
    	1). 当真正需要数据的时候,才要向数据库要数据,当加载属性的时候才发出sql语句,这种现象称为类的延迟加载
    		代理实例有以下特征:
    			代理类实例有如下特征:
    			由 Hibernate 在运行时采用 javassist 工具动态生成
    			Hibernate 创建代理类实例时, 仅初始化其 OID 属性
    •在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例
    	2). session.load方法可以做类的延迟加载,产生出来的是一个代理对象,产生的代理类是 classes的子类
    2. session.load方法和get方法的区别
    	1、session.load方法用延迟加载,但是session.get方法不用延迟加载
    	2、如果主键在数据库中没有对应的值,session.get方法返回的是null,但是不报错
    		session.load方法,当得到属性的时候,会报错ObjectNotFountException
    	3、session.load方法有可能会导致no session的异常,但是session.get方法不会
    3, 在配置文件中配置延迟加载
    	在Classes.hbm.xml文件中
    	<class name="com.itheima10.hibernate.domain.Classes" lazy="false">
    	如果lazy为false,则延迟加载失效
    4. manytoone的延迟加载(单端关联)
    	因为根据多的一方加载一的一方,加载一个数据,所以对效率影响不大,所以可以忽略
    5. 抓取策略
    	1). 策略为:先加载classes表中的数据,再根据每一个cid去student表中加载。所以
        如果含有子查询,这种策略会造成n+1条sql语句
    	2). hibernate底层会生成子查询,所以如果需求分析中含有子查询的sql语句,用这种策略
        效率比较高
    	3). 左外连接,一次性把classes和student的数据提取出来,但是如果含有子查询,
        则该策略失效
    	***该策略是在映射文件中通过set元素中的fetch属性作用的,一旦映射文件确定了以后就不能修改了。所以抓取策略只不过是hibernate提供的一种优化策略而已
    6. 提高性能总结
    	1、一级缓存通过减少与数据库的交互次数提高效率
        2、二级缓存通过把一些常用的不变的对象放入到缓存中提高效率
        3、查询缓存通过把数据放入到查询缓存中提高效率
        4、延迟加载是通过改变sql语句发出的时间来提高效率的
        5、抓取策略是通过发生怎么样的sql语句提高效率的
    	通过以上的5种方式可以尽量减少发出sql语句的数量,从而提高效率

    练习

    多对多双向
    	 一般操作
    	1、保存学生
    	2、保存课程
    	3、保存学生、保存课程
    	级联操作
    	4、保存学生级联保存课程
    	5、保存学生级联更新课程
    	6、保存课程级联保存学生
    	7、保存课程级联更新学生
    	8、更新课程级联操作学生
    	9、更新学生级联操作课程
    	   级联删除
    	关系操作
    	10、把一个学生加入到一个课程(建立关系)
    	11、把一个学生从一个课程转移到另外一个课程(重新建立关系)
    	12、把一个学生从某一个课程中移除(解除关系)
  • 相关阅读:
    Celery ---- 分布式队列神器 ---- 入门
    如何使用Python快速制作可视化报表----pyecharts
    django 使用 可视化包-Pyechart
    git & github 快速入门
    开发效率进阶
    windows编译 obs-studio
    python 控制vbox虚拟机
    pyqt实践——从裸机到打包安装
    测试darwin calendar 服务器
    centos 搭建 darwin calendar 服务器
  • 原文地址:https://www.cnblogs.com/codingpark/p/4328451.html
Copyright © 2011-2022 走看看