简介

今天学习之前闲扯一下。比如现在学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、把一个学生从某一个课程中移除(解除关系)