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、把一个学生从某一个课程中移除(解除关系)
  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/codingpark/p/4328451.html
Copyright © 2011-2022 走看看