Hibernate应用课堂.ppt_第1页
Hibernate应用课堂.ppt_第2页
Hibernate应用课堂.ppt_第3页
Hibernate应用课堂.ppt_第4页
Hibernate应用课堂.ppt_第5页
已阅读5页,还剩114页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Hibernate关系映射,在面向对象设计和实体模型关系中,对象间关系一般包括4种:一对一(one-to-one)、一对多(one-to-many)、多对一(many-to-one)、多对多(many-to-many) 对象是现实世界中具有唯一性的事物 一对一关联类型 :主键关联与唯一外键关联 一对一的主键关联形式是两张关联表通过主键形成一对一映射关系 唯一外键关联是两张表的主键值不同,使用一个新添加的字段来作为外键维持一对一关系 单向一对多只需在“一”的一方进行配置,反之就是单向多对一 双向一对多就是对单向一对多的一种改进,4.3 Hibernate关系映射,4.3.1 一对一关联 1. 共享主键方式 在注册某个论坛会员的时候,往往不但要填写登录账号和密码,还要填写其他的详细信息,这两部分信息通常会放在不同的表中,如表4.1、表4.2所示。,表4.1 登录表Login,表4.2 详细信息表Detail,4.3.1 一对一关联,登录表和详细信息表属于典型的一对一关联关系,可按共享主键方式进行。步骤如下: 创建Java项目,命名为“Hibernate_mapping”。 添加Hibernate开发能力,步骤同4.2.1节第4步。HibernateSessionFactory类同样位于org.util包下。 编写生成数据库表对应的Java类对象和映射文件。 Login表对应的POJO类Login.java:,package org.model; public class Login implements java.io.Serializable private int id; / ID号 private String username; / 登录账号 private String password; / 密码 private Detail detail; / 详细信息 / 省略上述各属性的getter和setter方法 ,4.3.1 一对一关联,Detail表对应的Detail.java:,package org.model; public class Detail implements java.io.Serializable private int id; / ID号 private String trueName; / 真实姓名 private String email; / 电子邮件 private Login login; / 登录信息 / 省略上述各属性的getter和setter方法 ,4.3.1 一对一关联,Login表与Login类的ORM映射文件Login.hbm.xml。, detail ,4.3.1 一对一关联,Detail表与Detail类的ORM映射文件Detail.hbm.xml:,name表示属性名字,class表示被关联的类的名字 cascade=“all”表明主控类的所有操作,对关联类也执行同样操作 lazy=“false“表示此关联为立即加载,4.3.1 一对一关联, 在hibernate.cfg.xml文件中加入配置映射文件的语句。 创建测试类。 在src文件夹下创建包test,在该包下建立测试类 “Test.java”。, Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); / 创建事务对象 Detail detail=new Detail(); Login login=new Login(); login.setUsername(“yanhong“); login.setPassword(“123“); detail.setTrueName(“严红“); detail.setEmail(““); /相互设置关联 login.setDetail(detail); detail.setLogin(login); /这样完成后就可以通过Session对象调用session.save(detail)来持久化该对象 session.save(detail); mit(); HibernateSessionFactory.closeSession(); ,4.3.1 一对一关联, 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Login表和Detail表的内容如图4.12、图4.13所示。,图4.12 Login表 图4.13 Detail表,4.3.1 一对一关联,2. 唯一外键方式 唯一外键的情况很多,例如,每个人对应一个房间。其实在很多情况下,可以是几个人住在同一个房间里面,就是多对一的关系。但是如果把这个多变成唯一,也就是说让一个人住一个房间,就变成了一对一的关系了,这就是前面说的一对一的关系其实是多对一关联关系的一种特殊情况。对应的Person表和Room表如表4.3、表4.4所示。,表4.3 Person表,表4.4 Room表,4.3.1 一对一关联,步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。,Person表对应的POJO类Person.java: package org.model; public class Person implements java.io.Serializable private Integer id; private String name; private Room room; / 省略上述各属性的getter和setter方法 Room表对应的POJO类Room.java: package org.model; public class Room implements java.io.Serializable private int id; private String address; private Person person; / 省略上述各属性的getter和setter方法 ,4.3.1 一对一关联,Person表与Person类的ORM映射文件Person.hbm.xml:, / 唯一性约束,实现一对一 ,4.3.1 一对一关联,Room表与Room类的ORM映射文件Room.hbm.xml:, / 指定关联类的属性名 ,4.3.1 一对一关联, 在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。 编写测试代码。在src文件夹下的包test的Test类中加入如下代码:, Person person=new Person(); person.setName(“liumin“); Room room=new Room(); room.setAddress(“NJ-S1-328“); person.setRoom(room); session.save(person); ,4.3.1 一对一关联, 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.14、图4.15所示。,图4.14 Person表 图4.15 Room表,4.3.2 多对一单向关联,只要把上例中的一对一的唯一外键关联实例稍微修改就可以变成多对一。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。其对应表不变,Person表对应的类也不变,对应的Person.hbm.xml文件修改如下:, / 主控类所有操作,对关联类也执行同样操作 ,4.3.2 多对一单向关联,而Room表不变,对应的POJO类如下: Room表与Room类的ORM映射文件Room.hbm.xml如下:,package org.model; public class Room implements java.io.Serializable private int id; private String address; / 省略上述各属性的getter和setter方法 ,4.3.2 多对一单向关联, 编写测试代码。 在src文件夹下的包test的Test类中加入如下代码:, Room room=new Room(); room.setAddress(“NJ-S1-328“); Person person=new Person(); person.setName(“liuyanmin“); person.setRoom(room); session.save(person); ,4.3.2 多对一单向关联, 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.16、图4.17所示。,图4.16 Person表 图4.17 Room表,4.3.3 一对多双向关联,下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。 Person表对应的POJO及其映射文件不用改变,现在来修改Room表对应的POJO类及其映射文件。对应的POJO:,package org.model; import java.util.HashSet; import java.util.Set; public class Room private int id; private String address; private Set person=new HashSet(); /集合,存放多个Person对象 /省略getter和setter方法 ,4.3.3 一对多双向关联,下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。 Room表与Room类的ORM映射文件Room.hbm.xml。, /级联程度 /充当外键的字段名 /被关联的类名字 ,表示关联关系的维护工作由谁来负责,默认false,表示由主控方负责;true表示由被控方负责。由于该例是双向操作,故需要设为false,也可不写,22,inverse,只有集合标记(set/map/list/array/bag)才有inverse属性 在 Hibernate 中,inverse 指定了关联关系的方向。关联 关系中 inverse = false 的为主动方,由主动方负责维护 关联关系 在没有设置 inverse=true 的情况下,父子两边都维护父子 关系 在 1-N 关系中,将 many 方设为主控方(inverse = false) 将有助于性能改善(如果要国家元首记住全国人民的名字,不 是太可能,但要让全国人民知道国家元首,就容易的多) 在 1-N 关系中,若将 1 方设为主控方 会额外多出 update 语句。 插入数据时无法同时插入外键列,因而无法为外键列添加非空约束,4.3.3 一对多双向关联,下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。 该配置文件中cascade配置的是级联程度,它有以下几种取值:,all:表示所有操作句在关联层级上进行连锁操作。 save-update:表示只有save和update操作进行连锁操作。 delete:表示只有delete操作进行连锁操作。 all-delete-orphan:在删除当前持久化对象时,它相当于delete;在保存或更新当前持久化对象时,它相当于save-update。另外它还可以删除与当前持久化对象断开关联关系的其他持久化对象。,4.3.3 一对多双向关联, 编写测试代码。 在src文件夹下的包test的Test类中加入如下代码:, Person person1=new Person(); Person person2=new Person(); Room room=new Room(); room.setAddress(“NJ-S1-328“); person1.setName(“李方方“); person2.setName(“王艳“); person1.setRoom(room); person2.setRoom(room); /这样完成后就可以通过Session对象 /调用session.save(person1)和session.save(person) /会自动保存room session.save(person1); session.save(person2); ,4.3.3 一对多双向关联, 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.18、图4.19所示。,图4.18 Person表 图4.19 Room表,4.3.3 一对多双向关联,由于是双向的,当然也可以从Room的一方来保存Person,在Test.java中加入如下代码:,. Person person1=new Person(); Person person2=new Person(); Room room=new Room(); person1.setName(“李方方“); person2.setName(“王艳“); Set persons=new HashSet(); persons.add(person1); persons.add(person2); room.setAddress(“NJ-S1-328“); room.setPerson(persons); /这样完成后,就可以通过Session对象 /调用session.save(room) /会自动保存person1和person2 .,4.3.3 一对多双向关联,运行程序,插入数据后,Person表和Room表的内容如图4.20、图4.21所示。,图4.20 Person表 图4.21 Room表,4.3.4 多对多关联,1. 多对多单向关联 学生和课程就是多对多的关系,一个学生可以选择多门课程,而一门课程又可以被多个学生选择。多对多关系在关系数据库中不能直接实现,还必须依赖一张连接表。如表4.6、表4.7和表4.8所示。,表4.6 学生表student,表4.7 课程表course,表4.8 连接表stu_cour,4.3.4 多对多关联,由于是单向的,也就是说从一方可以知道另一方,反之不行。这里以从学生知道选择了哪些课程为例实现多对多单向关联。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。 student表对应的POJO类如下:,package org.model; import java.util.HashSet; import java.util.Set; public class Student implements java.io.Serializable private int id; private String snumber; private String sname; private int sage; private Set courses=new HashSet(); /省略上述各属性的getter和setter方法 student表与Student类的ORM映射文件Student.hbm.xml。,4.3.4 多对多关联,course表对应的POJO如下:,package org.model; public class Course implements java.io.Serializable private int id; private String cnumber; private String cname; /省略上述各属性的getter和setter方法。 ,4.3.4 多对多关联,course表与Course类的ORM映射文件Course.hbm.xml 在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。, ,4.3.4 多对多关联, 编写测试代码。 在src文件夹下的包test的Test类中加入如下代码。, Course cour1=new Course(); Course cour2=new Course(); Course cour3=new Course(); cour1.setCnumber(“101“); cour1.setCname(“计算机基础“); cour2.setCnumber(“102“); cour2.setCname(“数据库原理“); cour3.setCnumber(“103“); cour3.setCname(“计算机原理“); Set courses=new HashSet(); courses.add(cour1); courses.add(cour2); courses.add(cour3); Student stu=new Student(); stu.setSnumber(“081101“); stu.setSname(“李方方“); stu.setSage(21); stu.setCourses(courses); session.save(stu); /设置完成后就可以通过Session对象调用session.save(stu)完成持久化 ,4.3.4 多对多关联, 运行程序,测试结果。 因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,student表、course表及连接表stu_cour表的内容如图4.22、图4.23、图4.24所示。,图4.22 student表,图4.23 course表 图4.24 stu_cour表,4.3.4 多对多关联,2. 多对多双向关联 首先将其Course表所对应的POJO对象修改成如下代码:,package org.model; import java.util.HashSet; import java.util.Set; public class Course implements java.io.Serializable private int id; private String cnumber; private String cname; private Set stus=new HashSet(); /省略上述各属性的getter和setter方法 ,4.3.4 多对多关联,2. 多对多双向关联 Course表与Course类的ORM映射文件Course.hbm.xml:, / 指定参照course表的外键名称 / 指定参照student表的外键名称 ,36,Hibernate关联映射小结,多对一(一对多)单向关联:只需在“多”或“一”进行配置,双向一对多需要在“一”和“多”都进行配置,37,级联:通常用在一对多和一对一关联中,主动方对象执行操作时,被关联对象(被动方)是否同步执行同一操作。 ,38,inverse=“true”控制反转,在一对多双向关联的情况下,“多”方作为作为主主动方比一方在应用的执行效率高。 在Hibernate中的一对多的单向或者双向关联的情况下,我们可以将“一”方控制权交给“多”方称为控制反转(inverse)。 ,39,延迟加载,Hibernate为了避免在关联查询中带来的无谓的性能开销,使用了延迟加载技术,仅在需要读取数据时才查询数据库 例如:在Category 和product的一对多关联查询中查询一个Category对象,同时读取其关联的多个product对象,则自动加载关联数据非常方便,如果仅需要获得Category对象的name属性值,而不关心其关联的product对象的属性值,则自动加载product对象的属性会导致无谓的系统开销。 Session对象的load方法可以利用持久化对象的延迟加载,而get方法则不可。,40,Hibernate提供三种形式的延迟加载:持久化对象、集合对象和属性的延迟加载。 如果一个数据库表中有一些大数据对象类型的字段,则加载该表对应的持久化对象必须每次都加载这些字段,而忽略其是否有用,从而带来大的性能开销。可以在需要使用这些字段对应的属性值时才在数据库中查询。 可以通过在property标签的lazy属性设置为true来激活属性的延迟加载。,41,持久化对象的延迟加载,42,public class HibernateTest / ehcache cache for collection public void testLazyLoading01() Session session =HibernateSessionFactoryUtil.getSessionFactory().getCurrentSession(); Transaction tx = session.beginTransaction(); Category category= (Category) session.load(Category.class, new Integer(1); / System.out.println(category.getName(); mit(); 运行后查看hibernate输出的SQL语句会发现hibernate没有输出任何的SQL语句,未真正查询数据库,因为load方法使用了持久对象的延迟加载,只有需要读取持久对象的属性时才会向数据库发出查询请求。 Load方法返回的不是真正的持久化对象,是其中的一个代理对象。,43,集合对象的延迟加载,对于集合属性,通常推荐使用延迟加载策略。所谓延迟加载就是当系统需要使用集合属性时才从数据库装载关联的数据。 Hibernate对集合属性默认采用延迟加载,在某些特殊的情况下为set, list,map等元素设置lazy=“false”属性来取消延迟加载。,44,集合对象的延迟加载,45,OSIV模式,为了更好的提高Hibernate的性能,Hibernate采用缓冲机制和延迟加载-关联的对象如果当时没必要就稍后加载。从而提高Hibernate的应用性能。 但是在Web中分层模式可能会因Session的关闭导致抛出org.hibernate.LazyInitializationException; 解决方案有2种: 1、关闭延迟加载。不推荐使用 2、延长Session对象的生命周期。这种方案比较好的。,46,首先写一个过滤器类,让这个类实现javax.servlet.Filter接口 private Transaction tx; private SessionFactory sessionFactory; Override public void destroy() / TODO Auto-generated method stub sessionFactory.close(); Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException / TODO Auto-generated method stub try Session session = HibernateSessionFactoryUtil.getSessionFactory().getCurrentSession(); tx=session.beginTransaction(); chain.doFilter(request, response); mit(); catch (Exception e) / TODO: handle exception System.out.println(e.getStackTrace(); tx.rollback(); Override public void init(FilterConfig arg0) throws ServletException / TODO Auto-generated method stub sessionFactory=HibernateSessionFactoryUtil.getSessionFactory(); ,47,继承映射,Hibernate 的继承映射可以理解持久化类之间的继承关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。,48,采用 subclass 元素的继承映射,在这种映射策略下,整个继承树的所有实例都保存在同一个表内。因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录是哪个类的实例-这个列被称为辨别者列(discriminator). 在这种映射策略下,使用 subclass 来映射子类,使用 discriminator-value 指定辨别者列的值,49,采用 subclass 元素的继承映射,50,采用 subclass 元素的继承映射,生成的表及插入的数据 person_table,注:所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类的实例在那些列根本没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中,51,采用 joined-subclass 元素的继承映射,采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。 在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键,该主键必须与父类标识属性的列名相同。但如果继承树的深度很深,可能查询一个子类实例时,需要跨越多个表,因为子类的数据一次保存在多个父类中。 子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中 采用 joined-subclass 元素的继承映射可以实现每个子类一张表,52,采用 joined-subclass 元素的继承映射,53,采用 joined-subclass 元素的继承映射,生成的表及插入的数据 person_table student_table,54,采用 union-subclass 元素的继承映射,采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中。 union-subclass 与 joined-subclass 映射策略类似:子类增加的属性也可以有非空约束 - 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。 与 joined-subclass 不同的是,子类实例的数据仅保存在子类表中,而在父类表中没有任何记录。 在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段加子类增加属性的总和 在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键.,55,采用 union-subclass 元素的继承映射,56,采用 union-subclass 元素的继承映射,生成的表及插入的数据 person_table student_table,57,三种继承映射方式的比较,58,映射复合主键,复合主键:指有多个字段同时做为主键 在Hibernate中,通过的子元素元素对复合主键进行定义(此元素和元素不能同时存在) 对于复合主键而言,有两种映射方式: 基于实体类属性的复合主键:复合主键由实体类中的某几个属性组成 基于主键类的复合主键:复合主键由单独的主键类进行描述 主键类必须实现java.io.Serializable接口 主键类必须实现equals方法和hashcode方法以作为不同数据之间的标识,59,映射基于实体类属性的复合主键,以学生成绩表(STUDENT_GRADE)为例,主键为(STUDENT_ID+SUBJECT_ID) 用映射文件配置如下: ,60,映射基于主键类的复合主键,以学生成绩表(STUDENT_GRADE)为例,主键为(STUDENT_ID+SUBJECT_ID) 为此创建独立的主键类StudentGradePK 用映射文件配置如下: ,61,Hibernate缓存深入详解,62,Hibernate缓存概述,Hibernate缓存机制对Hibernate的性能发挥一直处于一个极其重要的作用,它是持久层性能提升的关键。 hibernate缓存在应用系统中的位置 Hibernate缓存介于Hibernate应用和数据库之间,缓存中存放了数据库数据的拷贝。 其作用是减少访问数据库的频率,从而提高应用的运行性能。 Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做“缓存命中”),则就直接把命中的数据作为结果加以利用,避免的了建立数据库查询的性能损耗。,63,大纲,Hibernate缓存概述,1,Hibernate一级缓存(Session缓存),2,3,Hibernate二级缓存,4,查询缓存,64,Hibernate缓存分类,Hibernate提供了两级缓存: 一级缓存: Session级别的缓存 二级缓存: SessionFactory级别的全局缓存 Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝。 那么它们之间的区别是什么呢? 为了理解二者的区别,需要深入理解持久化层的缓存的一个特性:缓存的范围。,65,缓存的范围,缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。,事务范围 缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。一级缓存就属于事务范围。,66,缓存的范围(2),进程范围 缓存被进程范围内的所有事务共享。这些事务有可能并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。它的物理介质可以是内存或硬盘。,67,缓存的范围(3),集群范围 在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。 持久化层的第二级缓存就存在于进程范围或集群范围。,68,Hibernate的缓存机制,Hibernate中提供了两级Cache. 第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。随着session的关闭而消失,这一级别的缓存由hibernate管理的,一般情况下无需进行干预; 第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。,69,缓存对get load list iterator的影响,session的load方法,会先从一级缓存中查询当前标识符属性(id)对应的数据,如果未命中缓存,再判断持久化对象是否配置了二级缓存,如果配置了再从二级缓存中查询,否则从数据库中查询数据并缓存到对应的一级和二级缓存。 session的get方法,首先从一级缓存中查询,如果未命中,则直接从数据库中查询数据并缓存到相应的一级缓存中。 Query对象的list方法,首先检查是否配置了查询缓存,如果配置,则判断是否能命中缓存,如果未命中,则直接从数据库中查询数据并缓存到相应的一级、二级和查询缓存中。 Query对象iterator操作,首先从数据库中查询符合查询条件的标识符属性值,然后通过session的load方法查询当前标识符对应的数据。,70,理解一级缓存,(1)当应用程序调用Session接口的save()、update()、saveOrUpdate()时,如果Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。 (2)当调用Session接口的load()、get()以及Query查询接口的list() 方法时, 如果Session缓存中存在相 应的对象,就不需要到数据 库中检索。,71,Hibernate的一级缓存,Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象。 当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。,72,Session接口的用法,get()和load() 试图从数据库加载一个实体对象时,Session先判断对象是否存在,如果存在就不到数据库中检索。返回的对象都位于Session缓存中,接下来修改了持久化对象的属性后,当Session清理缓存时,会根据持久化对象的属性变化来同步更新数据库。 区别: (1)当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException异常,而get()方法返回null. (2)两者采用不同的检索策略。 默认情况下,load()方法采用延迟检索策略(Hibernate不会执行select语句,仅返回实体类的代理类实例,占用内存很少);而get()采用立即检索策略(Hibernate会立即执行select语句)。 使用场合: (1)如果加载一个对象的目的是为了访问它的各个属性,可以用get(); (2)如果加载一个对象的目的是为了删除它,或者建立与别的对象的关联关系,可以用load() ;,73,Hibernate的一级缓存(2),举例说明: public class Test public void get() Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get(TUser.class, 2); System.out.println(t.getName(); session.close(); 进行测试:在控制台打印出一条SQL语句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_ from test.t_user tuser0_ where tuser0_.id=? 说明进行了一次数据库的调用.,74,public class Test public void get() Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get(TUser.class, 2); System.out.println(t.getName(); TUser tt = (TUser)session.get(TUser.class, 2); System.out.println(tt.getName(); session.close(); 再进行测试:进行了两次查询,控制台仍然只打出一条SQL语句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_ from test.t_user tuser0_ where tuser0_.id=? 说明还是只进行了一次数据库的调用,75,Hibernate的一级缓存(3),再将代码更改如下: public class Test public void get() Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get(“hibernate.TUser“, 2); System.out.println(t.getName(); session.close(); Session session1 = HibernateSessionFactory.getSession(); TUser tt = (TUser)session1.get(“hibernate.TUser“, 2); System.out.println(tt.getName(); session1.close(); 继续测试:进行两次查询控制台打印两条SQL语句: Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=?,76,Session清理缓存,清理缓存是指Session按照缓存中对象的属性变化来同步更新数据库。 Session在清理缓存的时候会自动进行脏检查(dirty-check),如果发现Session缓存中的对象与数据库中相应的记录不一致,就会同步数据库。 Session是如何进行脏检查的呢? 当一个对象被加入到Session缓存时,Session 会为该对象的值类型的属性复制 一份快照。当Session清理缓存的时候,会进行脏检查,即比较对象的当前属性与它的快照,来判断对象的属性是否发生变化,如果发生变化,就称这个对象是“脏对象”,Session会根据脏对象的最新属性来执行相关的SQL语句,从而同步更新数据库。,77,Session何时清理缓存,session缓存中对象的属性每次发生变化,Session不会立即清理缓存及执行相关的update语句,而是在特定的时间点才清理缓存,这使得Session能够把几条相关的sql语句合并为一条sql语句,以便减少访问数据库的次数。 以下代码对dept对象的deptName属性修改了两次:,Transaction tx = session.biginTransaction(); Dept dept = (Dept)session.get(Dept.class,”001”); dept.setDeptName(“人事部”); dept.setDeptName(“人力资源部”); mit();,当Session清理缓存时,只会执行一条update语句,78,Session何时清理缓存,session会在下面的时间点清理缓存: (1)当应用程序调用org.hibernate.Transaction的commit()方法的时候 commit()方法先清理缓存,然后再向数据库提交事务。 (2) 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生变化,就会先清理缓存,使得Session缓存与数据库进行了同步,从而保证查询结果返回的是正确的数据。 (3) 当应用程序显式调用Session的flush()方法的时候,79,Sesion缓存的管理,第一级缓存在正常的情况下是由Hibernate自动维护的。 在特殊的情况下需要我们进行手动维护,Hibernate就提供了两个管理Session缓存的方法: (1)Session.evict(Object o) 将某个特定的对象从缓存中清除, 使用此方法有两种适用情形,一是在特定的操作(如批量处理),需要及时释放对象占用的内存。二是不希望当前Session继续运用此对象的状态变化来同步更新数据库。 (2)Session.clear() 清除缓存中的所有持久化对象。,1、在多数情况下并不提倡通过evit()和clear()来管理一级缓存。 2、管理一级缓存最有效的方法是采用合理的检索策略和检索方式来节省内存的开销。,80,Hibernate两级缓存机制,Hibernate的两级缓存机制: 如果在一级缓存中没有查询到相应的数据,可以到二级缓存中查找,如果在二级缓存中也没有找到数据,那么就只好查询数据库了。,81,Cache Providers(1),Hibernate本身并不提供二级缓存的产品化实现,而是为众多支持Hibernate的第三方缓存插件提供整和接口。 通过在vider_class属性中指

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论