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