Hibernate应用课堂.ppt

上传人:鲁** 文档编号:571407233 上传时间:2024-08-10 格式:PPT 页数:119 大小:1.14MB
返回 下载 相关 举报
Hibernate应用课堂.ppt_第1页
第1页 / 共119页
Hibernate应用课堂.ppt_第2页
第2页 / 共119页
Hibernate应用课堂.ppt_第3页
第3页 / 共119页
Hibernate应用课堂.ppt_第4页
第4页 / 共119页
Hibernate应用课堂.ppt_第5页
第5页 / 共119页
点击查看更多>>
资源描述

《Hibernate应用课堂.ppt》由会员分享,可在线阅读,更多相关《Hibernate应用课堂.ppt(119页珍藏版)》请在金锄头文库上搜索。

1、Hibernate关系映射关系映射1在面向对象设计和实体模型关系中,对象间关系在面向对象设计和实体模型关系中,对象间关系在面向对象设计和实体模型关系中,对象间关系在面向对象设计和实体模型关系中,对象间关系一般包括一般包括一般包括一般包括4 4种:一对一(种:一对一(种:一对一(种:一对一(one-to-oneone-to-one)、一对多)、一对多)、一对多)、一对多(one-to-manyone-to-many)、多对一()、多对一()、多对一()、多对一(many-to-onemany-to-one)、)、)、)、多对多(多对多(多对多(多对多(many-to-manymany-to-ma

2、ny)对象是现实世界中具有唯一性的事物对象是现实世界中具有唯一性的事物对象是现实世界中具有唯一性的事物对象是现实世界中具有唯一性的事物一对一关联类型一对一关联类型一对一关联类型一对一关联类型 :主键关联与唯一外键关联:主键关联与唯一外键关联:主键关联与唯一外键关联:主键关联与唯一外键关联一对一的主键关联形式是两张关联表通过主键形一对一的主键关联形式是两张关联表通过主键形一对一的主键关联形式是两张关联表通过主键形一对一的主键关联形式是两张关联表通过主键形成一对一映射关系成一对一映射关系成一对一映射关系成一对一映射关系唯一外键关联是两张表的主键值不同,使用一个唯一外键关联是两张表的主键值不同,使用

3、一个唯一外键关联是两张表的主键值不同,使用一个唯一外键关联是两张表的主键值不同,使用一个新添加的字段来作为外键维持一对一关系新添加的字段来作为外键维持一对一关系新添加的字段来作为外键维持一对一关系新添加的字段来作为外键维持一对一关系单向一对多只需在单向一对多只需在单向一对多只需在单向一对多只需在“ “一一一一” ”的一方进行配置,反之的一方进行配置,反之的一方进行配置,反之的一方进行配置,反之就是单向多对一就是单向多对一就是单向多对一就是单向多对一双向一对多就是对单向一对多的一种改进双向一对多就是对单向一对多的一种改进双向一对多就是对单向一对多的一种改进双向一对多就是对单向一对多的一种改进24

4、.3Hibernate关系映射关系映射4.3.1一对一关联一对一关联1.共享主键方式共享主键方式在注册某个论坛会员的时候,往往不但要填写登录账号和密码,还要填写其他的详细信息,这两部分信息通常会放在不同的表中,如表4.1、表4.2所示。字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述IDIDint(4)int(4)是是IDID号号USERNAMEUSERNAMEvarchar(20)varchar(20)登录账号登录账号PASSWORDPASSWORDvarchar(20)varchar(20)登录密码登录密码字字 段段 名名 称称数数 据据 类

5、类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述IDIDint(4)int(4)是是增增1 1IDID号号TRUENAMETRUENAMEvarchar(8)varchar(8)是是真实姓名真实姓名EMAILEMAILvarchar(50)varchar(50)是是电子邮件电子邮件表4.1 登录表Login表4.2 详细信息表Detail34.3.1一对一关联一对一关联登录表和详细信息表属于典型的一对一关联关系,可按共享主键方式进行。步骤如下: 创建Java项目,命名为“Hibernate_mapping”。 添加Hibernate开发能力,步骤同4.2.1节第4步。Hiberna

6、teSessionFactory类同样位于org.util包下。 编写生成数据库表对应的Java类对象和映射文件。Login表对应的POJO类Login.java:packageorg.model;publicclassLoginimplementsjava.io.Serializable privateintid;/ID号号 privateStringusername;/登录账号登录账号 privateStringpassword;/密码密码privateDetaildetail;/详细信息详细信息/省略上述各属性的省略上述各属性的getter和和setter方法方法44.3.1一对一关联一

7、对一关联Detail表对应的Detail.java:packageorg.model;publicclassDetailimplementsjava.io.Serializableprivateintid;/ID号号privateStringtrueName;/真实姓名真实姓名privateStringemail;/电子邮件电子邮件privateLoginlogin;/登录信息登录信息/省略上述各属性的省略上述各属性的getter和和setter方法方法54.3.1一对一关联一对一关联Login表与Login类的ORM映射文件Login.hbm.xml。!DOCTYPEhibernate-ma

8、ppingPUBLIC-/Hibernate/HibernateMappingDTD3.0/ENhttp:/ detaildetail propertyname=usernametype= propertyname=passwordtype= !-name- 64.3.1一对一关联一对一关联Detail表与Detail类的ORM映射文件Detail.hbm.xml:!DOCTYPEhibernate-mappingPUBLIC-/Hibernate/HibernateMappingDTD3.0/ENhttp:/ 在hibernate.cfg.xml文件中加入配置映射文件的语句。 创建测试类。在

9、src文件夹下创建包test,在该包下建立测试类 “Test.java”。 SessionSessionsessionsession= =HibernateSessionFactory.getSessionHibernateSessionFactory.getSession();();TransactionTransactiontsts= =session.beginTransactionsession.beginTransaction();/();/创建事务对象创建事务对象创建事务对象创建事务对象DetailDetaildetaildetail=newDetail();=newDetail(

10、);LoginLoginloginlogin=newLogin();=newLogin();login.setUsername(yanhonglogin.setUsername(yanhong););login.setPassword(123);login.setPassword(123);detail.setTrueNamedetail.setTrueName(严红严红严红严红););detail.setEmail();detail.setEmail();/ /相互设置关联相互设置关联相互设置关联相互设置关联login.setDetail(detail);detail.setLogin(lo

11、gin);/ /这样完成后就可以通过这样完成后就可以通过这样完成后就可以通过这样完成后就可以通过SessionSession对象调用对象调用对象调用对象调用session.save(detailsession.save(detail) )来持久化该对象来持久化该对象来持久化该对象来持久化该对象session.save(detailsession.save(detail); );mit();();HibernateSessionFactory.closeSessionHibernateSessionFactory.closeSession();();84.3.1一对一关联一对一关联 运行程序,测

12、试结果。因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Login表和Detail表的内容如图4.12、图4.13所示。 图4.12 Login表 图4.13 Detail表94.3.1一对一关联一对一关联2.唯一外键方式唯一外键方式唯一外键的情况很多,例如,每个人对应一个房间。其实在很多情况下,可以是几个人住在同一个房间里面,就是多对一的关系。但是如果把这个多变成唯一,也就是说让一个人住一个房间,就变成了一对一的关系了,这就是前面说的一对一的关系其实是多对一关联关系的一种特殊情况。对应的Person表和Roo

13、m表如表4.3、表4.4所示。字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述IdIdintint是是增增1 1IDID号号namenamevarchar(20)varchar(20)姓名姓名room_idroom_idint(20)int(20)是是房间号房间号字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述ididint(4)int(4)是是增增1 1IDID号号addressaddressvarchar(100)varchar(100)地址地址表4.3 Person表表4.4 Room表104

14、.3.1一对一关联一对一关联步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。Person表对应的表对应的POJO类类Person.java:packageorg.model;publicclassPersonimplementsjava.io.SerializableprivateIntegerid;privateStringname;privateRoomroom;/省略上述各属性的省略上述各属性的getter和和setter方法方法Room表对应的表对应的POJO类类Room.java:packageorg.mod

15、el;publicclassRoomimplementsjava.io.Serializableprivateintid;privateStringaddress;privatePersonperson;/省略上述各属性的省略上述各属性的getter和和setter方法方法114.3.1一对一关联一对一关联Person表与Person类的ORM映射文件Person.hbm.xml:/唯一性约束,实现一对一唯一性约束,实现一对一124.3.1一对一关联一对一关联Room表与Room类的ORM映射文件Room.hbm.xml:/指定关联类的属性名指定关联类的属性名134.3.1一对一关联一对一关联

16、 在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。 编写测试代码。在src文件夹下的包test的Test类中加入如下代码:Personperson=newPerson();person.setName(liumin);Roomroom=newRoom();room.setAddress(NJ-S1-328);person.setRoom(room);session.save(person);144.3.1一对一关联一对一关联 运行程序,测试结果。因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数

17、据后,Person表和Room表的内容如图4.14、图4.15所示。 图4.14 Person表 图4.15 Room表154.3.2多对一单向关联多对一单向关联只要把上例中的一对一的唯一外键关联实例稍微修改就可以变成多对一。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。其对应表不变,Person表对应的类也不变,对应的Person.hbm.xml文件修改如下:/主控类所有操作,对关联类也执行同样操作主控类所有操作,对关联类也执行同样操作164.3.2多对一单向关联多对一单向关联而Room表不变,对应的POJO类如下

18、:Room表与Room类的ORM映射文件Room.hbm.xml如下:packageorg.model;publicclassRoomimplementsjava.io.Serializableprivateintid;privateStringaddress;/省略上述各属性的省略上述各属性的getter和和setter方法方法174.3.2多对一单向关联多对一单向关联 编写测试代码。在src文件夹下的包test的Test类中加入如下代码:Roomroom=newRoom();room.setAddress(NJ-S1-328);Personperson=newPerson();person

19、.setName(liuyanmin);person.setRoom(room);session.save(person);184.3.2多对一单向关联多对一单向关联 运行程序,测试结果。因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.16、图4.17所示。 图4.16 Person表 图4.17 Room表194.3.3一对多双向关联一对多双向关联下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.mode

20、l包下编写生成数据库表对应的Java类对象和映射文件。Person表对应的POJO及其映射文件不用改变,现在来修改Room表对应的POJO类及其映射文件。对应的POJO:packageorg.model;importjava.util.HashSet;importjava.util.Set;publicclassRoomprivateintid;privateStringaddress;privateSetperson=newHashSet();/集合,存放多个集合,存放多个Person对象对象/省略省略getter和和setter方法方法204.3.3一对多双向关联一对多双向关联下面通过修改

21、4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。Room表与Room类的ORM映射文件Room.hbm.xml。/级联程度级联程度/充当外键的字段名充当外键的字段名/被关联的类名字被关联的类名字表示关联关系的维护工作表示关联关系的维护工作由谁来负责,默认由谁来负责,默认false,表示由主控方负责;表示由主控方负责;true表示由被控方负责。由于表示由被控方负责。由于该例是双向操作,故需要该例是双向操作,故需要设为设为false,也可不写,也可不写21inverse 只有只有只

22、有只有集合标记集合标记(set/map/list/array/bagset/map/list/array/bagset/map/list/array/bagset/map/list/array/bag)才有)才有)才有)才有inverseinverseinverseinverse属性属性属性属性在在在在 Hibernate Hibernate Hibernate Hibernate 中,中,中,中,inverse inverse inverse inverse 指定了关联关系的方向。关联指定了关联关系的方向。关联指定了关联关系的方向。关联指定了关联关系的方向。关联 关系中关系中关系中关系中 i

23、nverse = false inverse = false inverse = false inverse = false 的为主动方,由主动方负责维护的为主动方,由主动方负责维护的为主动方,由主动方负责维护的为主动方,由主动方负责维护 关联关系关联关系关联关系关联关系在没有设置在没有设置在没有设置在没有设置 inverse=true inverse=true inverse=true inverse=true 的情况下,父子两边都维护父子的情况下,父子两边都维护父子的情况下,父子两边都维护父子的情况下,父子两边都维护父子 关系关系关系关系 在在在在 1-N 1-N 1-N 1-N 关系中,

24、将关系中,将关系中,将关系中,将 many many many many 方设为主控方方设为主控方方设为主控方方设为主控方(inverse = false) (inverse = false) (inverse = false) (inverse = false) 将有助于性能改善将有助于性能改善将有助于性能改善将有助于性能改善( ( ( (如果要国家元首记住全国人民的名字,不如果要国家元首记住全国人民的名字,不如果要国家元首记住全国人民的名字,不如果要国家元首记住全国人民的名字,不 是太可能,但要让全国人民知道国家元首,就容易的多是太可能,但要让全国人民知道国家元首,就容易的多是太可能,但要

25、让全国人民知道国家元首,就容易的多是太可能,但要让全国人民知道国家元首,就容易的多) ) ) )在在在在 1-N 1-N 1-N 1-N 关系中,若将关系中,若将关系中,若将关系中,若将 1 1 1 1 方设为主控方方设为主控方方设为主控方方设为主控方 会额外多出会额外多出会额外多出会额外多出 update update update update 语句。语句。语句。语句。 插入数据时无法同时插入外键列,因而无法为外键列添加插入数据时无法同时插入外键列,因而无法为外键列添加插入数据时无法同时插入外键列,因而无法为外键列添加插入数据时无法同时插入外键列,因而无法为外键列添加非空约束非空约束非空约

26、束非空约束224.3.3一对多双向关联一对多双向关联下面通过修改4.3.2节的例子来完成双向多对一的实现。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。该配置文件中cascade配置的是级联程度,它有以下几种取值:all:表示所有操作句在关联层级上进行连锁操作。:表示所有操作句在关联层级上进行连锁操作。save-update:表示只有:表示只有save和和update操作进行连锁操作。操作进行连锁操作。delete:表示只有:表示只有delete操作进行连锁操作。操作进行连锁操作。all-delete-orphan:

27、在删除当前持久化对象时,它相当于:在删除当前持久化对象时,它相当于delete;在保存或更新;在保存或更新当前持久化对象时,它相当于当前持久化对象时,它相当于save-update。另外它还可以删除与当前持久化对。另外它还可以删除与当前持久化对象断开关联关系的其他持久化对象。象断开关联关系的其他持久化对象。234.3.3一对多双向关联一对多双向关联 编写测试代码。在src文件夹下的包test的Test类中加入如下代码:Personperson1=newPerson();Personperson2=newPerson();Roomroom=newRoom();room.setAddress(NJ

28、-S1-328);person1.setName(李方方李方方);person2.setName(王艳王艳);person1.setRoom(room);person2.setRoom(room);/这样完成后就可以通过这样完成后就可以通过Session对象对象/调用调用session.save(person1)和和session.save(person)/会自动保存会自动保存roomsession.save(person1);session.save(person2);244.3.3一对多双向关联一对多双向关联 运行程序,测试结果。因为该程序为Java Application,所以可以直接运

29、行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,Person表和Room表的内容如图4.18、图4.19所示。 图4.18 Person表 图4.19 Room表254.3.3一对多双向关联一对多双向关联由于是双向的,当然也可以从Room的一方来保存Person,在Test.java中加入如下代码:.Personperson1=newPerson();Personperson2=newPerson();Roomroom=newRoom();person1.setName(李方方李方方);person2.setName(王艳王艳);Setpersons=newHashSe

30、t();persons.add(person1);persons.add(person2);room.setAddress(NJ-S1-328);room.setPerson(persons);/这样完成后,就可以通过这样完成后,就可以通过Session对象对象/调用调用session.save(room)/会自动保存会自动保存person1和和person2.264.3.3一对多双向关联一对多双向关联运行程序,插入数据后,Person表和Room表的内容如图4.20、图4.21所示。 图4.20 Person表 图4.21 Room表274.3.4多对多关联多对多关联1.多对多单向关联多对多

31、单向关联学生和课程就是多对多的关系,一个学生可以选择多门课程,而一门课程又可以被多个学生选择。多对多关系在关系数据库中不能直接实现,还必须依赖一张连接表。如表4.6、表4.7和表4.8所示。字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述IDIDintint是是增增1 1IDID号号SNUMBERSNUMBERvarchar(10)varchar(10)学号学号SNAMESNAMEvarchar(10)varchar(10)是是姓名姓名SAGESAGEintint是是年龄年龄字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许

32、许 为为 空空描描 述述IDIDintint是是增增1 1IDID号号CNUMBERCNUMBERvarchar(10)varchar(10)课程号课程号CNAMECNAMEvarchar(20)varchar(20)是是课程名课程名表4.6 学生表student表4.7 课程表course字字 段段 名名 称称数数 据据 类类 型型主主 键键自自 增增允允 许许 为为 空空描描 述述SIDSIDintint是是学生学生IDID号号CIDCIDintint是是课程课程IDID号号表4.8 连接表stu_cour284.3.4多对多关联多对多关联由于是单向的,也就是说从一方可以知道另一方,反之不

33、行。这里以从学生知道选择了哪些课程为例实现多对多单向关联。步骤如下: 在项目Hibernate_mapping的org.model包下编写生成数据库表对应的Java类对象和映射文件。student表对应的POJO类如下:packageorg.model;importjava.util.HashSet;importjava.util.Set;publicclassStudentimplementsjava.io.Serializableprivateintid;privateStringsnumber;privateStringsname;privateintsage;privateSetcou

34、rses=newHashSet();/省略上述各属性的省略上述各属性的getter和和setter方法方法student表与表与Student类的类的ORM映射映射文件文件Student.hbm.xml。294.3.4多对多关联多对多关联course表对应的POJO如下:packageorg.model;publicclassCourseimplementsjava.io.Serializableprivateintid;privateStringcnumber;privateStringcname;/省略上述各属性的省略上述各属性的getter和和setter方法。方法。304.3.4多对多

35、关联多对多关联 course表与Course类的ORM映射文件Course.hbm.xml 在hibernate.cfg.xml文件中加入如下的配置映射文件的语句。314.3.4多对多关联多对多关联 编写测试代码。在src文件夹下的包test的Test类中加入如下代码。Coursecour1=newCourse();Coursecour2=newCourse();Coursecour3=newCourse();cour1.setCnumber(101);cour1.setCname(计算机基础计算机基础);cour2.setCnumber(102);cour2.setCname(数据库原理数据

36、库原理);cour3.setCnumber(103);cour3.setCname(计算机原理计算机原理);Setcourses=newHashSet();courses.add(cour1);courses.add(cour2);courses.add(cour3);Studentstu=newStudent();stu.setSnumber(081101);stu.setSname(李方方李方方);stu.setSage(21);stu.setCourses(courses);session.save(stu);/设置完成后就可以通过设置完成后就可以通过Session对象调用对象调用ses

37、sion.save(stu)完成持久化完成持久化324.3.4多对多关联多对多关联 运行程序,测试结果。因为该程序为Java Application,所以可以直接运行。在完全没有操作数据库的情况下,程序就完成了对数据的插入。插入数据后,student表、course表及连接表stu_cour表的内容如图4.22、图4.23、图4.24所示。图4.22 student表 图4.23 course表 图4.24 stu_cour表334.3.4多对多关联多对多关联2.多对多双向关联多对多双向关联首先将其Course表所对应的POJO对象修改成如下代码:packageorg.model;import

38、java.util.HashSet;importjava.util.Set;publicclassCourseimplementsjava.io.Serializableprivateintid;privateStringcnumber;privateStringcname;privateSetstus=newHashSet();/省略上述各属性的省略上述各属性的getter和和setter方法方法344.3.4多对多关联多对多关联2.多对多双向关联多对多双向关联Course表与Course类的ORM映射文件Course.hbm.xml:/指定参照指定参照course表的外键名称表的外键名称/

39、指定参照指定参照student表的外键名称表的外键名称35Hibernate关联映射小结多对一(一对多)单向关联:只需在多对一(一对多)单向关联:只需在多对一(一对多)单向关联:只需在多对一(一对多)单向关联:只需在“ “多多多多” ”或或或或“ “一一一一” ”进行配置,双向一对多需要在进行配置,双向一对多需要在进行配置,双向一对多需要在进行配置,双向一对多需要在“ “一一一一” ”和和和和“ “多多多多” ”都进行配置都进行配置都进行配置都进行配置36级联:通常用在一对多和一对一关联中,主动方级联:通常用在一对多和一对一关联中,主动方级联:通常用在一对多和一对一关联中,主动方级联:通常用在

40、一对多和一对一关联中,主动方对象执行操作时,被关联对象(被动方)是否同对象执行操作时,被关联对象(被动方)是否同对象执行操作时,被关联对象(被动方)是否同对象执行操作时,被关联对象(被动方)是否同步执行同一操作。步执行同一操作。步执行同一操作。步执行同一操作。setname= keycolumn=one-to-many/37inverse=inverse=true”true”控制反转控制反转在一对多双向关联的情况下,在一对多双向关联的情况下,在一对多双向关联的情况下,在一对多双向关联的情况下,“ “多多多多” ”方作为作为主主动方作为作为主主动方作为作为主主动方作为作为主主动方比一方在应用的执

41、行效率高。方比一方在应用的执行效率高。方比一方在应用的执行效率高。方比一方在应用的执行效率高。在在在在HibernateHibernate中的一对多的单向或者双向关联的情况下,中的一对多的单向或者双向关联的情况下,中的一对多的单向或者双向关联的情况下,中的一对多的单向或者双向关联的情况下,我们可以将我们可以将我们可以将我们可以将“ “一一一一” ”方控制权交给方控制权交给方控制权交给方控制权交给“ “多多多多” ”方称为控制反转方称为控制反转方称为控制反转方称为控制反转(inverse)(inverse)。setname= columnname=/one-to-many/38延迟加载Hiber

42、nateHibernate为了避免在关联查询中带来的无谓的为了避免在关联查询中带来的无谓的为了避免在关联查询中带来的无谓的为了避免在关联查询中带来的无谓的性能开销,使用了延迟加载技术,仅在需要读取性能开销,使用了延迟加载技术,仅在需要读取性能开销,使用了延迟加载技术,仅在需要读取性能开销,使用了延迟加载技术,仅在需要读取数据时才查询数据库数据时才查询数据库数据时才查询数据库数据时才查询数据库例如:在例如:在例如:在例如:在CategoryCategory和和和和productproduct的一对多关联查的一对多关联查的一对多关联查的一对多关联查询中查询一个询中查询一个询中查询一个询中查询一个C

43、ategoryCategory对象,同时读取其关联对象,同时读取其关联对象,同时读取其关联对象,同时读取其关联的多个的多个的多个的多个productproduct对象,则自动加载关联数据非常对象,则自动加载关联数据非常对象,则自动加载关联数据非常对象,则自动加载关联数据非常方便,如果仅需要获得方便,如果仅需要获得方便,如果仅需要获得方便,如果仅需要获得CategoryCategory对象的对象的对象的对象的namename属属属属性值,而不关心其关联的性值,而不关心其关联的性值,而不关心其关联的性值,而不关心其关联的productproduct对象的属性值,对象的属性值,对象的属性值,对象的属

44、性值,则自动加载则自动加载则自动加载则自动加载productproduct对象的属性会导致无谓的系对象的属性会导致无谓的系对象的属性会导致无谓的系对象的属性会导致无谓的系统开销。统开销。统开销。统开销。SessionSession对象的对象的对象的对象的loadload方法可以利用持久化对象的方法可以利用持久化对象的方法可以利用持久化对象的方法可以利用持久化对象的延迟加载,而延迟加载,而延迟加载,而延迟加载,而getget方法则不可。方法则不可。方法则不可。方法则不可。39HibernateHibernate提供三种形式的延迟加载:持久化对提供三种形式的延迟加载:持久化对提供三种形式的延迟加载

45、:持久化对提供三种形式的延迟加载:持久化对象、集合对象和属性的延迟加载。象、集合对象和属性的延迟加载。象、集合对象和属性的延迟加载。象、集合对象和属性的延迟加载。如果一个数据库表中有一些大数据对象类型的字如果一个数据库表中有一些大数据对象类型的字如果一个数据库表中有一些大数据对象类型的字如果一个数据库表中有一些大数据对象类型的字段,则加载该表对应的持久化对象必须每次都加段,则加载该表对应的持久化对象必须每次都加段,则加载该表对应的持久化对象必须每次都加段,则加载该表对应的持久化对象必须每次都加载这些字段,而忽略其是否有用,从而带来大的载这些字段,而忽略其是否有用,从而带来大的载这些字段,而忽略

46、其是否有用,从而带来大的载这些字段,而忽略其是否有用,从而带来大的性能开销。可以在需要使用这些字段对应的属性性能开销。可以在需要使用这些字段对应的属性性能开销。可以在需要使用这些字段对应的属性性能开销。可以在需要使用这些字段对应的属性值时才在数据库中查询。值时才在数据库中查询。值时才在数据库中查询。值时才在数据库中查询。可以通过在可以通过在可以通过在可以通过在propertyproperty标签的标签的标签的标签的lazylazy属性设置为属性设置为属性设置为属性设置为truetrue来激活属性的延迟加载。来激活属性的延迟加载。来激活属性的延迟加载。来激活属性的延迟加载。40持久化对象的延迟加

47、载classname=com.v512.examples.Categorytable=CATEGORYlazy=trueidname=idtype=propertyname=nametype=propertyname=descriptiontype=setname=productscascade=save-updateinverse=truelazy=false keycolumn=one-to-manyclass=com.v512.examples.Product/41publicclasspublicclassHibernateTestHibernateTest /ehcacheehcac

48、hecacheforcollectioncacheforcollectionpublicvoidtestLazyLoading01()publicvoidtestLazyLoading01()SessionSessionsessionsession = =HibernateSessionFactoryUtil.getSessionFactory().getCurrentHibernateSessionFactoryUtil.getSessionFactory().getCurrentSessionSession();();TransactionTransactiontxtx=session.b

49、eginTransactionsession.beginTransaction();();CategoryCategorycategorycategory=(Category)=(Category)session.load(Category.classsession.load(Category.class,newInteger(1);,newInteger(1);/System.out.println(category.getNameSystem.out.println(category.getName();();mit();(); 运行后查看运行后查看运行后查看运行后查看hibernateh

50、ibernate输出的输出的输出的输出的SQLSQL语句会发现语句会发现语句会发现语句会发现hibernatehibernate没有输出任没有输出任没有输出任没有输出任何的何的何的何的SQLSQL语句,未真正查询数据库,因为语句,未真正查询数据库,因为语句,未真正查询数据库,因为语句,未真正查询数据库,因为loadload方法使用了持久对象方法使用了持久对象方法使用了持久对象方法使用了持久对象的延迟加载,只有需要读取持久对象的属性时才会向数据库发出查的延迟加载,只有需要读取持久对象的属性时才会向数据库发出查的延迟加载,只有需要读取持久对象的属性时才会向数据库发出查的延迟加载,只有需要读取持久对

51、象的属性时才会向数据库发出查询请求。询请求。询请求。询请求。LoadLoad方法返回的不是真正的持久化对象,是其中的一个代理对象。方法返回的不是真正的持久化对象,是其中的一个代理对象。方法返回的不是真正的持久化对象,是其中的一个代理对象。方法返回的不是真正的持久化对象,是其中的一个代理对象。42集合对象的延迟加载对于集合属性,通常推荐使用对于集合属性,通常推荐使用对于集合属性,通常推荐使用对于集合属性,通常推荐使用延迟加载策略延迟加载策略。所。所。所。所谓延迟加载就是当系统需要使用集合属性时才从谓延迟加载就是当系统需要使用集合属性时才从谓延迟加载就是当系统需要使用集合属性时才从谓延迟加载就是当

52、系统需要使用集合属性时才从数据库装载关联的数据。数据库装载关联的数据。数据库装载关联的数据。数据库装载关联的数据。HibernateHibernateHibernateHibernate对集合属性默认采用延迟加载,在某对集合属性默认采用延迟加载,在某对集合属性默认采用延迟加载,在某对集合属性默认采用延迟加载,在某些特殊的情况下为些特殊的情况下为些特殊的情况下为些特殊的情况下为set, listset, listset, listset, list,mapmapmapmap等元素设置等元素设置等元素设置等元素设置lazy=lazy=lazy=lazy=“ “falsefalsefalsefals

53、e” ”属性来取消延迟加载。属性来取消延迟加载。属性来取消延迟加载。属性来取消延迟加载。43集合对象的延迟加载setname=productscascade=save-updateinverse=truelazy=true keycolumn=one-to-manyclass=com.v512.examples.Product/44OSIV模式 为了更好的提高为了更好的提高为了更好的提高为了更好的提高HibernateHibernate的性能,的性能,的性能,的性能,HibernateHibernate采采采采用缓冲机制和延迟加载用缓冲机制和延迟加载用缓冲机制和延迟加载用缓冲机制和延迟加载-

54、-关联的对象如果当时没关联的对象如果当时没关联的对象如果当时没关联的对象如果当时没必要就稍后加载。从而提高必要就稍后加载。从而提高必要就稍后加载。从而提高必要就稍后加载。从而提高HibernateHibernate的应用性的应用性的应用性的应用性能。能。能。能。但是在但是在但是在但是在WebWeb中分层模式可能会因中分层模式可能会因中分层模式可能会因中分层模式可能会因SessionSession的关闭的关闭的关闭的关闭导致抛出导致抛出导致抛出导致抛出org.hibernate.LazyInitializationExceptionorg.hibernate.LazyInitialization

55、Exception; ;解决方案有解决方案有解决方案有解决方案有2 2种:种:种:种:1 1、关闭延迟加载。不推荐使用、关闭延迟加载。不推荐使用、关闭延迟加载。不推荐使用、关闭延迟加载。不推荐使用2 2、延长、延长、延长、延长SessionSession对象的生命周期。这种方案比对象的生命周期。这种方案比对象的生命周期。这种方案比对象的生命周期。这种方案比较好的。较好的。较好的。较好的。45首先写一个过滤器类,让这个类实现首先写一个过滤器类,让这个类实现首先写一个过滤器类,让这个类实现首先写一个过滤器类,让这个类实现javax.servlet.Filterjavax.servlet.Filte

56、r接口接口接口接口privateTransactionprivateTransactiontxtx; ;privateprivateSessionFactorySessionFactory sessionFactorysessionFactory; ;OverrideOverridepublicvoiddestroy()publicvoiddestroy()/TODOAuto-generatedmethodstub/TODOAuto-generatedmethodstubsessionFactory.closesessionFactory.close();(); OverrideOverrid

57、epublicvoidpublicvoiddoFilter(ServletRequestdoFilter(ServletRequestrequest,request,ServletResponseServletResponseresponse,response,FilterChainFilterChainchain)throwschain)throwsIOExceptionIOException, ,ServletExceptionServletException /TODOAuto-generatedmethodstub/TODOAuto-generatedmethodstubtrytryS

58、essionSessionsessionsession=HibernateSessionFactoryUtil.getSessionFactory().getCurrentSessionHibernateSessionFactoryUtil.getSessionFactory().getCurrentSession();();txtx= =session.beginTransactionsession.beginTransaction();();chain.doFilter(requestchain.doFilter(request,response);,response);mit();();

59、catch(Exceptione)catch(Exceptione)/TODO:handleexception/TODO:handleexceptionSystem.out.println(e.getStackTraceSystem.out.println(e.getStackTrace();();tx.rollbacktx.rollback();(); OverrideOverridepublicvoidpublicvoidinit(FilterConfiginit(FilterConfigarg0)throwsarg0)throwsServletExceptionServletExcept

60、ion /TODOAuto-generatedmethodstub/TODOAuto-generatedmethodstubsessionFactorysessionFactory= =HibernateSessionFactoryUtil.getSessionFactoryHibernateSessionFactoryUtil.getSessionFactory();(); 46继承映射Hibernate Hibernate Hibernate Hibernate 的继承映射可以理解持久化类之间的继承的继承映射可以理解持久化类之间的继承的继承映射可以理解持久化类之间的继承的继承映射可以理解持

61、久化类之间的继承关系。例如:人和学生之间的关系。学生继承了人,关系。例如:人和学生之间的关系。学生继承了人,关系。例如:人和学生之间的关系。学生继承了人,关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,可以认为学生是一个特殊的人,如果对人进行查询,可以认为学生是一个特殊的人,如果对人进行查询,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。学生的实例也将被得到。学生的实例也将被得到。学生的实例也将被得到。47采用 subclass 元素的继承映射在这种映射策略下,整个继承树的所有实例在这种映射策略下,整个继承树的所有实例都保存在同

62、一个表内。因为父类和子类的实都保存在同一个表内。因为父类和子类的实例全部保存在同一个表中,因此需要在该表例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录是哪内增加一列,使用该列来区分每行记录是哪个类的实例个类的实例-这个列被称为辨别者列这个列被称为辨别者列(discriminator).(discriminator).在这种映射策略下,使用在这种映射策略下,使用 subclass subclass 来映射来映射子类,使用子类,使用 discriminator-value discriminator-value 指定辨别指定辨别者列的值者列的值48采用 subclass

63、元素的继承映射49采用 subclass 元素的继承映射生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据 person_tableperson_table注:所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么注:所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类的实例在那些列根本没有值,这将引起数据库完整性冲突,导致父类的实例无父类的实例在那些列根本没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中法保存到数据库中50采用采用 joined-subclass joined-subclass 元素的继承映射元

64、素的继承映射采用这种映射策略时,父类实例保存在父类表中,子类实例由采用这种映射策略时,父类实例保存在父类表中,子类实例由采用这种映射策略时,父类实例保存在父类表中,子类实例由采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类父类表和子类表共同存储。因为子类实例也是一个特殊的父类父类表和子类表共同存储。因为子类实例也是一个特殊的父类父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类实例,因此必然也包含了父类实例的属性。于是将子类和父类实例,因此必然也包含了父类实例的属性。于是将子类

65、和父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类共有的属性保存在父类表中,子类增加的属性,则保存在子类共有的属性保存在父类表中,子类增加的属性,则保存在子类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。表中。表中。表中。在这种映射策略下,无须使用鉴别者列,但需要为每个子类使在这种映射策略下,无须使用鉴别者列,但需要为每个子类使在这种映射策略下,无须使用鉴别者列,但需要为每个子类使在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用用用用 keykey元素映射共有主键,该主键必须与父类标识属性的列元素映射共有主键

66、,该主键必须与父类标识属性的列元素映射共有主键,该主键必须与父类标识属性的列元素映射共有主键,该主键必须与父类标识属性的列名相同。但如果继承树的深度很深,可能查询一个子类实例时,名相同。但如果继承树的深度很深,可能查询一个子类实例时,名相同。但如果继承树的深度很深,可能查询一个子类实例时,名相同。但如果继承树的深度很深,可能查询一个子类实例时,需要跨越多个表,因为子类的数据一次保存在多个父类中。需要跨越多个表,因为子类的数据一次保存在多个父类中。需要跨越多个表,因为子类的数据一次保存在多个父类中。需要跨越多个表,因为子类的数据一次保存在多个父类中。子类增加的属性可以添加非空约束。因为子类的属性

67、和父类的子类增加的属性可以添加非空约束。因为子类的属性和父类的子类增加的属性可以添加非空约束。因为子类的属性和父类的子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中属性没有保存在同一个表中属性没有保存在同一个表中属性没有保存在同一个表中采用采用采用采用 joined-subclassjoined-subclass元素的继承映射可以实现元素的继承映射可以实现元素的继承映射可以实现元素的继承映射可以实现每个子类一每个子类一每个子类一每个子类一张表张表张表张表51采用采用 joined-subclass joined-subclass 元素的继承映射元素的继承映射52采

68、用采用 joined-subclass joined-subclass 元素的继承映射元素的继承映射生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据 person_tableperson_table student_tablestudent_table53采用采用 union-subclass union-subclass 元素的继承映射元素的继承映射采用采用采用采用 union-subclassunion-subclass元素可以实现将元素可以实现将元素可以实现将元素可以实现将每一个实体每一个实体每一个实体每一个实体对象映射到一个独立的表中。对象映射到一个独立

69、的表中。对象映射到一个独立的表中。对象映射到一个独立的表中。union-subclass union-subclass union-subclass union-subclass 与与与与 joined-subclass joined-subclass joined-subclass joined-subclass 映射策略类映射策略类映射策略类映射策略类似:子类增加的属性也可以有非空约束似:子类增加的属性也可以有非空约束似:子类增加的属性也可以有非空约束似:子类增加的属性也可以有非空约束 - - - - 即父即父即父即父类实例的数据保存在父表中,而子类实例的数据保类实例的数据保存在父表中,而

70、子类实例的数据保类实例的数据保存在父表中,而子类实例的数据保类实例的数据保存在父表中,而子类实例的数据保存在子类表中。存在子类表中。存在子类表中。存在子类表中。与与与与 joined-subclass joined-subclass joined-subclass joined-subclass 不同的是,子类实例的数据不同的是,子类实例的数据不同的是,子类实例的数据不同的是,子类实例的数据仅保存在子类表中,而在父类表中没有任何记录。仅保存在子类表中,而在父类表中没有任何记录。仅保存在子类表中,而在父类表中没有任何记录。仅保存在子类表中,而在父类表中没有任何记录。在这种映射策略下,子类表的字段

71、会比父类表的映在这种映射策略下,子类表的字段会比父类表的映在这种映射策略下,子类表的字段会比父类表的映在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段射字段要多,因为子类表的字段等于父类表的字段射字段要多,因为子类表的字段等于父类表的字段射字段要多,因为子类表的字段等于父类表的字段加子类增加属性的总和加子类增加属性的总和加子类增加属性的总和加子类增加属性的总和在这种映射策略下,既不需要使用鉴别者列,也无在这种映射策略下,既不需要使用鉴别者列,也无在这种映射策略下,既不需要使用鉴别者列,也无在这种映射策略下,既不需要使用鉴别者列,也无须使用须使用须使用须使

72、用 key key key key 元素来映射共有主键元素来映射共有主键元素来映射共有主键元素来映射共有主键. . . .54采用采用 union-subclass union-subclass 元素的继承映射元素的继承映射55采用采用 union-subclass union-subclass 元素的继承映射元素的继承映射生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据生成的表及插入的数据 person_tableperson_tableperson_tableperson_table student_tablestudent_tablestudent_tablestudent_

73、table56三种继承映射方式的比较 union-subclasssubclassjoined-subclass57映射复合主键复合主键:指有多个字段同时做为主键复合主键:指有多个字段同时做为主键复合主键:指有多个字段同时做为主键复合主键:指有多个字段同时做为主键在在在在HibernateHibernate中,通过中,通过中,通过中,通过的子元素的子元素的子元素的子元素元素对复合主键进行定义元素对复合主键进行定义元素对复合主键进行定义元素对复合主键进行定义( (此元此元此元此元素和素和素和素和元素不能同时存在元素不能同时存在元素不能同时存在元素不能同时存在) )对于复合主键而言,有两种映射方式

74、:对于复合主键而言,有两种映射方式:对于复合主键而言,有两种映射方式:对于复合主键而言,有两种映射方式: 基于实体类属性的复合主键:复合主键由实体类中的基于实体类属性的复合主键:复合主键由实体类中的基于实体类属性的复合主键:复合主键由实体类中的基于实体类属性的复合主键:复合主键由实体类中的某几个属性组成某几个属性组成某几个属性组成某几个属性组成 基于主键类的复合主键:复合主键由单独的主键类进基于主键类的复合主键:复合主键由单独的主键类进基于主键类的复合主键:复合主键由单独的主键类进基于主键类的复合主键:复合主键由单独的主键类进行描述行描述行描述行描述 主键类必须实现主键类必须实现主键类必须实现

75、主键类必须实现java.io.Serializablejava.io.Serializable接口接口接口接口 主键类必须实现主键类必须实现主键类必须实现主键类必须实现equalsequals方法和方法和方法和方法和hashcodehashcode方法以作为不方法以作为不方法以作为不方法以作为不同数据之间的标识同数据之间的标识同数据之间的标识同数据之间的标识58映射基于实体类属性的复合主键以学生成绩表以学生成绩表以学生成绩表以学生成绩表(STUDENT_GRADE)(STUDENT_GRADE)为例,主键为为例,主键为为例,主键为为例,主键为(STUDENT_ID+SUBJECT_ID)(ST

76、UDENT_ID+SUBJECT_ID)用映射文件配置如下:用映射文件配置如下:用映射文件配置如下:用映射文件配置如下:key-propertyname=“type=“string”column=“STUDENT_ID”/key-propertyname=“type=“string”column=“SUBJECT_ID”/59映射基于主键类的复合主键以学生成绩表以学生成绩表以学生成绩表以学生成绩表(STUDENT_GRADE)(STUDENT_GRADE)为例,主键为为例,主键为为例,主键为为例,主键为(STUDENT_ID+SUBJECT_ID)(STUDENT_ID+SUBJECT_ID)

77、为此创建独立的主键类为此创建独立的主键类为此创建独立的主键类为此创建独立的主键类StudentGradePKStudentGradePK用映射文件配置如下:用映射文件配置如下:用映射文件配置如下:用映射文件配置如下:composite-id key-propertyname=“type=“string”column=“STUDENT_ID”/key-propertyname=“type=“string”column=“SUBJECT_ID”/60Hibernate缓存深入详解61Hibernate缓存概述 Hibernate缓存机制对缓存机制对Hibernate的性能发挥一直处于一个极其重的性

78、能发挥一直处于一个极其重要的作用,它是持久层性能提升的关键。要的作用,它是持久层性能提升的关键。 hibernate缓存在应用系统中的位置 Hibernate缓存介于缓存介于Hibernate应用和数据库之间,缓存中存放了应用和数据库之间,缓存中存放了数据库数据的拷贝。数据库数据的拷贝。其作用是减少访问数据库的频率,从而提高应用其作用是减少访问数据库的频率,从而提高应用的运行性能。的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据查询,如果在缓存中找到了需要的数据(我们把这称做我们把这

79、称做“缓存命中缓存命中”),则就直接把命中的数据作为结果加以利用,避免的了建立数据库查询则就直接把命中的数据作为结果加以利用,避免的了建立数据库查询的性能损耗。的性能损耗。62大纲大纲 HibernateHibernate缓存概述缓存概述1HibernateHibernate一级缓存(一级缓存(SessionSession缓存)缓存)23 HibernateHibernate二级缓存二级缓存 4查询缓存查询缓存63Hibernate缓存分类 Hibernate提供了两级缓存:提供了两级缓存:一级缓存:一级缓存:Session级别的缓存级别的缓存二级缓存:二级缓存:SessionFactory级

80、别的全局缓存级别的全局缓存Hibernate的这两级缓存都位于持久化层,存放的都的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝。是数据库数据的拷贝。那么它们之间的区别是什么呢?那么它们之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存为了理解二者的区别,需要深入理解持久化层的缓存的一个特性:的一个特性:缓存的范围缓存的范围。64缓存的范围 缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类围分为三类。事务范围事务范围缓存只能被当前事务访问。缓存的生命周缓存只能被当前事务访问。缓存的生命周期依赖于事务

81、的生命周期,当事务结束时,缓存也就结期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。缓存的介质是内存。事务可以是数据库事束生命周期。缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。数据通常采用相互关联的的对象形式。一级缓存就属于一级缓存就属于事务范围。事务范围。65缓存的范围(2) 进程范围进程范围 缓存被进程范围内的所有事务共享。这些缓存被进程范围内的所有事务共享。这些事务有可能并发访问缓存,因此必须对缓存采取必要的事务有可能并发访问缓存,因此必须对缓存采取必要的

82、事务隔离机制。缓存的生命周期依赖于进程的生命周期,事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。它的物理介质进程结束时,缓存也就结束了生命周期。它的物理介质可以是内存或硬盘。可以是内存或硬盘。66缓存的范围(3)集群范围集群范围在集群环境中,缓存被一个机器或者多个在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形据的一致性,缓存中的

83、数据通常采用对象的松散数据形式。式。持久化层的第二级缓存就存在于进程范围或集群范持久化层的第二级缓存就存在于进程范围或集群范围。围。67Hibernate的缓存机制HibernateHibernate中提供了两级中提供了两级中提供了两级中提供了两级CacheCache. . 第一级别的缓存是第一级别的缓存是第一级别的缓存是第一级别的缓存是SessionSession级别的缓存,它是属于事务级别的缓存,它是属于事务级别的缓存,它是属于事务级别的缓存,它是属于事务范围的缓存。范围的缓存。范围的缓存。范围的缓存。随着随着随着随着sessionsession的关闭而消失,的关闭而消失,的关闭而消失,的

84、关闭而消失,这一级别的这一级别的这一级别的这一级别的缓存由缓存由缓存由缓存由hibernatehibernate管理的,一般情况下无需进行干预;管理的,一般情况下无需进行干预;管理的,一般情况下无需进行干预;管理的,一般情况下无需进行干预; 第二级别的缓存是第二级别的缓存是第二级别的缓存是第二级别的缓存是SessionFactorySessionFactory级别的缓存,它是级别的缓存,它是级别的缓存,它是级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可属于进程范围或群集范围的缓存。这一级别的缓存可属于进程范围或群集范围的缓存。这一级别的缓存可属于进程范围或群集范围的缓存。这一级

85、别的缓存可以进行配置和更改,并且可以动态加载和卸载。以进行配置和更改,并且可以动态加载和卸载。以进行配置和更改,并且可以动态加载和卸载。以进行配置和更改,并且可以动态加载和卸载。 HibernateHibernate还为查询结果提供了一个查询缓存,它依赖还为查询结果提供了一个查询缓存,它依赖还为查询结果提供了一个查询缓存,它依赖还为查询结果提供了一个查询缓存,它依赖于第二级缓存。于第二级缓存。于第二级缓存。于第二级缓存。68缓存对get load list iterator的影响sessionsession的的的的loadload方法,会先从一级缓存中查询当前标识符方法,会先从一级缓存中查询当

86、前标识符方法,会先从一级缓存中查询当前标识符方法,会先从一级缓存中查询当前标识符属性(属性(属性(属性(idid)对应的数据,如果未命中缓存,再判断持久)对应的数据,如果未命中缓存,再判断持久)对应的数据,如果未命中缓存,再判断持久)对应的数据,如果未命中缓存,再判断持久化对象是否配置了二级缓存,如果配置了再从二级缓存化对象是否配置了二级缓存,如果配置了再从二级缓存化对象是否配置了二级缓存,如果配置了再从二级缓存化对象是否配置了二级缓存,如果配置了再从二级缓存中查询,否则从数据库中查询数据并缓存到对应的一级中查询,否则从数据库中查询数据并缓存到对应的一级中查询,否则从数据库中查询数据并缓存到对

87、应的一级中查询,否则从数据库中查询数据并缓存到对应的一级和二级缓存。和二级缓存。和二级缓存。和二级缓存。sessionsession的的的的getget方法,首先从一级缓存中查询,如果未命方法,首先从一级缓存中查询,如果未命方法,首先从一级缓存中查询,如果未命方法,首先从一级缓存中查询,如果未命中,则直接从数据库中查询数据并缓存到相应的一级缓中,则直接从数据库中查询数据并缓存到相应的一级缓中,则直接从数据库中查询数据并缓存到相应的一级缓中,则直接从数据库中查询数据并缓存到相应的一级缓存中。存中。存中。存中。QueryQuery对象的对象的对象的对象的listlist方法,首先检查是否配置了查询

88、缓存,方法,首先检查是否配置了查询缓存,方法,首先检查是否配置了查询缓存,方法,首先检查是否配置了查询缓存,如果配置,则判断是否能命中缓存,如果未命中,则直如果配置,则判断是否能命中缓存,如果未命中,则直如果配置,则判断是否能命中缓存,如果未命中,则直如果配置,则判断是否能命中缓存,如果未命中,则直接从数据库中查询数据并缓存到相应的一级、二级和查接从数据库中查询数据并缓存到相应的一级、二级和查接从数据库中查询数据并缓存到相应的一级、二级和查接从数据库中查询数据并缓存到相应的一级、二级和查询缓存中。询缓存中。询缓存中。询缓存中。QueryQuery对象对象对象对象iteratoriterator

89、操作,首先从数据库中查询符合查询操作,首先从数据库中查询符合查询操作,首先从数据库中查询符合查询操作,首先从数据库中查询符合查询条件的标识符属性值,然后通过条件的标识符属性值,然后通过条件的标识符属性值,然后通过条件的标识符属性值,然后通过sessionsession的的的的loadload方法查方法查方法查方法查询当前标识符对应的数据。询当前标识符对应的数据。询当前标识符对应的数据。询当前标识符对应的数据。69理解一级缓存 (1)当应用程序调用)当应用程序调用Session接口的接口的save()、update()、saveOrUpdate()时,如果时,如果Session缓存中还不存在相应

90、的对象,缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。就会把该对象加入到第一级缓存中。(2)当调用)当调用Session接口的接口的load()、get()以及以及Query查查询接口的询接口的list()方法时,方法时,如果如果Session缓存中存在相缓存中存在相应的对象,就不需要到数据应的对象,就不需要到数据库中检索。库中检索。70Hibernate的一级缓存SessionSessionSessionSession为应用程序提供了两个管理缓存的方法:为应用程序提供了两个管理缓存的方法:为应用程序提供了两个管理缓存的方法:为应用程序提供了两个管理缓存的方法:e

91、vict(Object obj)evict(Object obj)evict(Object obj)evict(Object obj):从缓存中清除参数指定:从缓存中清除参数指定:从缓存中清除参数指定:从缓存中清除参数指定的持久化对象。的持久化对象。的持久化对象。的持久化对象。clear()clear()clear()clear():清空缓存中所有持久化:清空缓存中所有持久化:清空缓存中所有持久化:清空缓存中所有持久化对象。对象。对象。对象。当清理缓存时,当清理缓存时,当清理缓存时,当清理缓存时,HibernateHibernateHibernateHibernate会根据缓存中对象的状会根据

92、缓存中对象的状会根据缓存中对象的状会根据缓存中对象的状态变化来同步更新数据库。态变化来同步更新数据库。态变化来同步更新数据库。态变化来同步更新数据库。71Session接口的用法get()和和load()试图从数据库加载一个实体对象时,试图从数据库加载一个实体对象时,Session先判断对象是否存在,先判断对象是否存在,如果存在就不到数据库中检索。返回的对象都位于如果存在就不到数据库中检索。返回的对象都位于Session缓存中,接下缓存中,接下来修改了持久化对象的属性后,当来修改了持久化对象的属性后,当Session清理缓存时,会根据持久化对清理缓存时,会根据持久化对象的属性变化来同步更新数据

93、库。象的属性变化来同步更新数据库。区别:区别:(1)当数据库中不存在与)当数据库中不存在与OID对应的记录时,对应的记录时,load()方法抛出方法抛出ObjectNotFoundException异常,而异常,而get()方法返回方法返回null.(2)两者采用不同的检索策略。)两者采用不同的检索策略。默认情况下,默认情况下,load()方法采用延迟检索策略(方法采用延迟检索策略(Hibernate不会执行不会执行select语句,仅返回实体类的代理类实例,占用内存很少);而语句,仅返回实体类的代理类实例,占用内存很少);而get()采用采用立即检索策略(立即检索策略(Hibernate会立

94、即执行会立即执行select语句)。语句)。使用场合:使用场合:(1)如果加载一个对象的目的是为了访问它的各个属性,可以用)如果加载一个对象的目的是为了访问它的各个属性,可以用get();(2)如果加载一个对象的目的是为了删除它,或者建立与别的对象的)如果加载一个对象的目的是为了删除它,或者建立与别的对象的关联关系,可以用关联关系,可以用load();72Hibernate的一级缓存(2)举例说明举例说明: : publicclassTestpublicclassTestpublicvoidget()publicvoidget()Sessionsession=Sessionsession=Hi

95、bernateSessionFactory.getSession();HibernateSessionFactory.getSession(); TUsert=TUsert=(TUser)session.get(TUser.class,2);(TUser)session.get(TUser.class,2);System.out.println(t.getName();System.out.println(t.getName(); session.close();session.close();进行测试进行测试进行测试进行测试: :在控制台打印出一条在控制台打印出一条在控制台打印出一条在控制台

96、打印出一条SQLSQL语句语句语句语句:Hibernate:selecttuser0_.idasid0_0_,:Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_fromtest.t_usertuser0_.nameasname0_0_fromtest.t_usertuser0_wheretuser0_.id=?tuser0_wheretuser0_.id=?说明进行了一次数说明进行了一次数说明进行了一次数说明进行了一次数据库的调用据库的调用据库的调用据库的调用. .73publicclassTestpublicclassTest

97、publicvoidget()publicvoidget()SessionSessionsessionsession=HibernateSessionFactory.getSessionHibernateSessionFactory.getSession();();TUserTUsert=(t=(TUser)session.get(TUser.classTUser)session.get(TUser.class, ,2);2);System.out.println(t.getNameSystem.out.println(t.getName();();TUserTUser tt tt=( (TU

98、ser)session.get(TUser.classTUser)session.get(TUser.class,2);,2);System.out.println(tt.getNameSystem.out.println(tt.getName();();session.closesession.close();();再进行测试再进行测试再进行测试再进行测试: :进行了两次查询进行了两次查询进行了两次查询进行了两次查询, ,控制台仍然只打出一条控制台仍然只打出一条控制台仍然只打出一条控制台仍然只打出一条SQLSQL语句语句语句语句:Hibernate:selecttuser0_.idasid0

99、_0_,:Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_fromtuser0_.nameasname0_0_fromtest.t_usertest.t_usertuser0_tuser0_wheretuser0_.id=?wheretuser0_.id=?说明还是只进行了一次数据库的说明还是只进行了一次数据库的说明还是只进行了一次数据库的说明还是只进行了一次数据库的调用调用调用调用 74Hibernate的一级缓存(3) 再将代码更改如下再将代码更改如下再将代码更改如下再将代码更改如下: :publicclassTestpub

100、licclassTestpublicvoidget()publicvoidget()Sessionsession=Sessionsession=HibernateSessionFactory.getSession();HibernateSessionFactory.getSession();TUsert=(TUser)session.get(hibernate.TUser,2);TUsert=(TUser)session.get(hibernate.TUser,2);System.out.println(t.getName();System.out.println(t.getName();se

101、ssion.close();session.close();Sessionsession1=Sessionsession1=HibernateSessionFactory.getSession();HibernateSessionFactory.getSession();TUsertt=(TUser)session1.get(hibernate.TUser,2);TUsertt=(TUser)session1.get(hibernate.TUser,2);System.out.println(tt.getName();System.out.println(tt.getName();sessio

102、n1.close();session1.close();继续测试继续测试继续测试继续测试: :进行两次查询控制台打印两条进行两次查询控制台打印两条进行两次查询控制台打印两条进行两次查询控制台打印两条SQLSQL语句语句语句语句: :Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_,Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_,tuser0_.sexassex0_0_fromtest.t_usertuser0_wheretuser0_.id=?tuser0_.s

103、exassex0_0_fromtest.t_usertuser0_wheretuser0_.id=?Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_,Hibernate:selecttuser0_.idasid0_0_,tuser0_.nameasname0_0_,tuser0_.sexassex0_0_fromtest.t_usertuser0_wheretuser0_.id=?tuser0_.sexassex0_0_fromtest.t_usertuser0_wheretuser0_.id=?75Session清理缓存 清理

104、缓存清理缓存是指是指Session按照缓存中对象的属性变化来按照缓存中对象的属性变化来同步更新数据库。同步更新数据库。Session在清理缓存的时候会自动进行脏检查(在清理缓存的时候会自动进行脏检查(dirty-check),如果发现),如果发现Session缓存中的对象与数据库中相缓存中的对象与数据库中相应的记录不一致,就会同步数据库。应的记录不一致,就会同步数据库。Session是如何进行脏检查的呢?是如何进行脏检查的呢?当一个对象被加入到当一个对象被加入到Session缓存时,缓存时,Session会为会为该对象的值类型的属性复制该对象的值类型的属性复制一份快照。当一份快照。当Sessi

105、on清理缓清理缓存的时候,会进行脏检查,即比较对象的当前属性与它的存的时候,会进行脏检查,即比较对象的当前属性与它的快照,来判断对象的属性是否发生变化,如果发生变化,快照,来判断对象的属性是否发生变化,如果发生变化,就称这个对象是就称这个对象是“脏对象脏对象”,Session会根据脏对象的最会根据脏对象的最新属性来执行相关的新属性来执行相关的SQL语句,从而同步更新数据库。语句,从而同步更新数据库。76Session何时清理缓存 session缓存中对象的属性每次发生变化,缓存中对象的属性每次发生变化,Session不会立即清不会立即清理缓存及执行相关的理缓存及执行相关的update语句,而是

106、在特定的时间点才清理缓存,语句,而是在特定的时间点才清理缓存,这使得这使得Session能够把几条相关的能够把几条相关的sql语句合并为一条语句合并为一条sql语句,以便减语句,以便减少访问数据库的次数。少访问数据库的次数。以下代码对以下代码对dept对象的对象的deptName属性修改了两次:属性修改了两次:Transaction tx = session.biginTransaction();Dept dept = (Dept)session.get(Dept.class,”001”);dept.setDeptName(“人事部人事部”);dept.setDeptName(“人力资源部人力

107、资源部”);mit();当当Session清理缓存时,只会执行一条清理缓存时,只会执行一条update语句语句77Session何时清理缓存 session会在下面的时间点清理缓存:会在下面的时间点清理缓存:(1)当应用程序调用)当应用程序调用org.hibernate.Transaction的的commit()方法的时候方法的时候commit()方法先清理缓存,然后再向数据库提交事务。方法先清理缓存,然后再向数据库提交事务。(2)当应用程序执行一些查询操作时,如果缓存中持久化当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生变化,就会先清理缓存,使得对象的属性已经发生变化,就会

108、先清理缓存,使得Session缓存与数据库进行了同步,从而保证查询结果返缓存与数据库进行了同步,从而保证查询结果返回的是正确的数据。回的是正确的数据。(3)当应用程序显式调用当应用程序显式调用Session的的flush()方法的时候方法的时候78Sesion缓存的管理 第一级缓存在正常的情况下是由第一级缓存在正常的情况下是由Hibernate自动维护的。自动维护的。在特殊的情况下需要我们进行手动维护,在特殊的情况下需要我们进行手动维护,Hibernate就提供了两就提供了两个管理个管理Session缓存的方法:缓存的方法:(1)Session.evict(Objecto)将某个特定的对象从缓

109、存中清除,将某个特定的对象从缓存中清除,使用此方法有两种适用情形,一是在特定的操作(如批量处理),使用此方法有两种适用情形,一是在特定的操作(如批量处理),需要及时释放对象占用的内存。二是不希望当前需要及时释放对象占用的内存。二是不希望当前Session继续运用此继续运用此对象的状态变化来同步更新数据库。对象的状态变化来同步更新数据库。(2)Session.clear()清除缓存中的所有持久化对象。清除缓存中的所有持久化对象。1、在多数情况下并不提倡通过、在多数情况下并不提倡通过evit()和和clear()来管理一级缓存。来管理一级缓存。2、管理一级缓存最有效的方法是采用合理的检索策略和检索

110、方式来节省内存的、管理一级缓存最有效的方法是采用合理的检索策略和检索方式来节省内存的开销。开销。79Hibernate两级缓存机制 Hibernate的两级缓存机制:的两级缓存机制:如果在一级缓存中没有查询到相应的数据,如果在一级缓存中没有查询到相应的数据,可以到二级缓存中查找,如果在二级缓存中也没可以到二级缓存中查找,如果在二级缓存中也没有找到数据,那么就只好查询数据库了。有找到数据,那么就只好查询数据库了。80CacheProviders(1) Hibernate本身并不提供二级缓存的产品化实本身并不提供二级缓存的产品化实现,而是为众多支持现,而是为众多支持Hibernate的第三方缓存插

111、件的第三方缓存插件提供整和接口。提供整和接口。通过在通过在hibernate.cache.provider_class属性中属性中指定指定org.hibernate.cache.CacheProvider的某个的某个实现的类名实现的类名,你可以选择让你可以选择让Hibernate使用哪个缓存使用哪个缓存实现。实现。Hibernate打包一些开源缓存实现,提供对打包一些开源缓存实现,提供对它们的内置支持。它们的内置支持。除此之外,你也可以实现你自己的缓存,将它除此之外,你也可以实现你自己的缓存,将它们插入到系统中。们插入到系统中。 81CacheProviders(2)CacheCachePro

112、vider ClassProvider ClassCluster Cluster SupportedSupportedQuery Query Cache Cache SupportedSupportedEhcacheEhcacheorg.hibernate.cache.EhCacheProviderorg.hibernate.cache.EhCacheProvideryesyes yesyesOSCacheOSCacheorg.hibernate.cache.OSCacheProviderorg.hibernate.cache.OSCacheProvideryesyesyesyesSwarm

113、Swarm CacheCacheorg.hibernate.cache.SwarmCacheProviderorg.hibernate.cache.SwarmCacheProvideryesyesnonoJossCacheJossCacheorg.hibernate.cache.TreeCacheProviderorg.hibernate.cache.TreeCacheProvideryesyesyesyes Hibernate支持以下类型的缓存插件:支持以下类型的缓存插件:为了把这些缓存插件集成到为了把这些缓存插件集成到Hibernate中,中,Hibernate提供提供了了org.hibe

114、rnate.cache.CacheProvider接口,它是缓存接口,它是缓存插件和与插件和与Hibernate之间的适配器。之间的适配器。Hibernate分别为这些分别为这些缓存插件提供了内置的缓存插件提供了内置的CacheProvider实现实现。 82使用:使用:使用:使用:propertyororg.hibernate.cache.EhCacheProviderg.hibernate.cache.EhCacheProvider/property来指定缓存提供商。即有谁来提供缓存的功能。来指定缓存提供商。即有谁来提供缓存的功能。来指定缓存提供商。即有谁来提供缓存的功能。来指定缓存提供商

115、。即有谁来提供缓存的功能。 EhcacheEhcache配置配置83Hibernate的二级缓存Hibernate二级缓存是二级缓存是SessionFactory级的缓存级的缓存,它允许多它允许多个个Session间共享间共享,使用时需要使用第使用时需要使用第三方的缓存组件三方的缓存组件,新版新版Hibernate将将EHcache作为默认的二级缓存实现作为默认的二级缓存实现.84缓存的并发访问策略(缓存的并发访问策略(1) cache concurrency strategy 当两个并发的事务同时访问数据库相同数当两个并发的事务同时访问数据库相同数据的时候,有可能出现五类并发访问问题,据的时

116、候,有可能出现五类并发访问问题,因此必须采用必要的事务隔离措施。同样,因此必须采用必要的事务隔离措施。同样,两个并发的事务同时访问缓存的相同数据时,两个并发的事务同时访问缓存的相同数据时,也有可能出现各类并发问题。也有可能出现各类并发问题。因此必须为因此必须为Hibernate二级缓存设定适当二级缓存设定适当的并发访问策略,每一种策略对应一种事务的并发访问策略,每一种策略对应一种事务隔离级别。隔离级别。85缓存的并发访问策略(缓存的并发访问策略(2) cache concurrency strategytransactionaltransactional(事(事务务型)型)仅仅仅仅在受管理的在

117、受管理的在受管理的在受管理的环环环环境中适用境中适用境中适用境中适用提供提供提供提供Repeatable ReadRepeatable Read事事事事务务务务隔离隔离隔离隔离级别级别级别级别适用适用适用适用经经经经常被常被常被常被读读读读,很少修改的数据,很少修改的数据,很少修改的数据,很少修改的数据可以防止可以防止可以防止可以防止脏读脏读脏读脏读和不可重复和不可重复和不可重复和不可重复读读读读的并的并的并的并发问题发问题发问题发问题缓缓缓缓存支持事存支持事存支持事存支持事务务务务,发发发发生异常的生异常的生异常的生异常的时时时时候,候,候,候,缓缓缓缓存也能存也能存也能存也能够够够够回回回

118、回滚滚滚滚read-writeread-write(读读写型)写型)提供提供提供提供Read CommittedRead Committed事事事事务务务务隔离隔离隔离隔离级别级别级别级别在非集群的在非集群的在非集群的在非集群的环环环环境中适用境中适用境中适用境中适用适用经常被读,很少修改的数据适用经常被读,很少修改的数据适用经常被读,很少修改的数据适用经常被读,很少修改的数据可以防止脏读可以防止脏读可以防止脏读可以防止脏读更新更新更新更新缓缓缓缓存的存的存的存的时时时时候会候会候会候会锁锁锁锁定定定定缓缓缓缓存中的数据存中的数据存中的数据存中的数据nonstrictnonstrict-rea

119、d-write-read-write(非(非严严格格读读写型)写型)适适适适用用用用极极极极少少少少被被被被修修修修改改改改,偶偶偶偶尔尔尔尔允允允允许许许许脏脏脏脏读读读读的的的的数数数数据据据据(两两两两个个个个事事事事务务务务同同同同时时时时修修修修改改改改数数数数据据据据的的的的情情情情况况况况很很很很少少少少见见见见)不保不保不保不保证缓证缓证缓证缓存和数据存和数据存和数据存和数据库库库库中数据的一致性中数据的一致性中数据的一致性中数据的一致性为缓为缓为缓为缓存数据存数据存数据存数据设设设设置很短的置很短的置很短的置很短的过过过过期期期期时间时间时间时间,从而尽量避免,从而尽量避免,

120、从而尽量避免,从而尽量避免脏读脏读脏读脏读不不不不锁锁锁锁定定定定缓缓缓缓存中的数据存中的数据存中的数据存中的数据read-onlyread-only(只(只读读型)型)适用适用适用适用从来不会被修改从来不会被修改的数据(如参考数据)的数据(如参考数据)的数据(如参考数据)的数据(如参考数据)在此模式下,如果在此模式下,如果在此模式下,如果在此模式下,如果对对对对数据数据数据数据进进进进行更新操作,会有异常行更新操作,会有异常行更新操作,会有异常行更新操作,会有异常事事事事务务务务隔离隔离隔离隔离级别级别级别级别低,并低,并低,并低,并发发发发性能高性能高性能高性能高在集群在集群在集群在集群环

121、环环环境中也能完美运作境中也能完美运作境中也能完美运作境中也能完美运作86CacheConcurrencyStrategySupported各种缓存插件对缓存并发访问策略的支持情况:各种缓存插件对缓存并发访问策略的支持情况:cachecachetransactionaltransactionalread-writeread-writenonstrictnonstrict-read-write-read-writeread-onlyread-onlyEhcacheEhcachenonoyesyesyesyesyesyesOSCacheOSCachenonoyesyesyesyesyesyesSw

122、arm CacheSwarm CachenonononoyesyesyesyesJossCacheJossCacheyesyesnonononoyesyes87二级缓存的配置配置二级缓存主要包含以下几个步骤:配置二级缓存主要包含以下几个步骤:启用二级缓存;启用二级缓存;选择需要进行二级缓存的持久化类,设置它的缓选择需要进行二级缓存的持久化类,设置它的缓存并发访问策略;存并发访问策略;选择合适的缓存插件;选择合适的缓存插件;为命名缓存设置数据过期策略;为命名缓存设置数据过期策略;88二级缓存的配置(1) 启用二级缓存:在启用二级缓存:在Hibernate的配置文件中配置属性的配置文件中配置属性注

123、意:注意:此属性对指定此属性对指定的类缺省为的类缺省为true。选择需要二级缓存的持久化类,设置它的选择需要二级缓存的持久化类,设置它的缓存并发访问策略缓存并发访问策略transactional|read-write|nonstrict-read-write|read-onlyHibernate允许在分散的各个映射文件中为持久化类设置允许在分散的各个映射文件中为持久化类设置二级缓存,也允许在二级缓存,也允许在Hibernate的配置文件中集中设置二级缓存,的配置文件中集中设置二级缓存,指定指定和和元素,统一配置。元素,统一配置。后一种方式更有利于代码维护。后一种方式更有利于代码维护。hiber

124、nate.cache.use_second_level_cache = true89二级缓存的配置(2)在映射文件中设置二级缓存在映射文件中设置二级缓存.hbm.xml:类或者集合映射的类或者集合映射的“元素元素”的详细用法:的详细用法:usage:(必须必须)说明了缓存的同步策略说明了缓存的同步策略:transactional、read-write、nonstrict-read-write或或read-only。region :(可选可选,默认为类或者集合的名字默认为类或者集合的名字)指定二级缓存的区域名指定二级缓存的区域名include :(可选可选,默认为默认为all)如果取值为如果取值

125、为non-lazy,表示当缓存一个对象时,表示当缓存一个对象时,不会缓存它的映射为延迟加载的属性。不会缓存它的映射为延迟加载的属性。 90二级缓存的配置例如: . 注意:注意:1、元素必须紧跟元素 2、 Hibernate只会缓存对象的简单属性的值, 如果要缓存集合属性,必须在集合元素中也加入子元素,而Hibernate仅仅是把与当前持久对象关联的对象的ID存放到缓存中。如果希望把整个关联的对象的所有数据都存入缓存,则要在相应关联的对象的映射文件中配置元素。91二级缓存的配置(5)选择合适的缓存插件选择合适的缓存插件:在配置文件指定在配置文件指定CacheProvider 每一种缓存插件都有自

126、带的配置文件,需要手工编辑配每一种缓存插件都有自带的配置文件,需要手工编辑配置文件置文件,在配置文件中需要为每个命名缓存设置在配置文件中需要为每个命名缓存设置数据过期策数据过期策略略.如:如:Ehcache插件插件ehcache.xmlJbosscache插件插件treecache.xml下面我们以下面我们以ehcache为例进行介绍。为例进行介绍。 org.hibernate.cache.EhCacheProvider 92ehcache.xml样例 93配置文件ehcache.xml 把把ehcache.xml放在放在classpath下,自动加载。下,自动加载。元素,指定一个文件目录,当

127、元素,指定一个文件目录,当ehcache把缓存写入硬盘的时候,把缓存写入硬盘的时候,就把数据写到这个文件目录下。就把数据写到这个文件目录下。元素,设置缓存的默认数据过期策略元素,设置缓存的默认数据过期策略元素,元素,设置具体的命名缓存的数据过期策略设置具体的命名缓存的数据过期策略 每个命名缓存代表一个缓存区域,每个缓存区域都有自己的数据过期策略。每个命名缓存代表一个缓存区域,每个缓存区域都有自己的数据过期策略。每个需要缓存的持久化类都要这样配置。如果没有配置,每个需要缓存的持久化类都要这样配置。如果没有配置,hibernate会在启动会在启动的时候警告你,然后使用的时候警告你,然后使用defa

128、ultCache的配置。的配置。94Hibernate的二级缓存(1)HibernateHibernate的二级缓存策略的一般过程如下:的二级缓存策略的一般过程如下:的二级缓存策略的一般过程如下:的二级缓存策略的一般过程如下:1)1)条件查询的时候,总是发出一条条件查询的时候,总是发出一条条件查询的时候,总是发出一条条件查询的时候,总是发出一条select*fromselect*fromtable_namewhere.table_namewhere.(选择所有字段)这样的(选择所有字段)这样的(选择所有字段)这样的(选择所有字段)这样的SQLSQL语语语语句查询数据库,一次获得所有的数据对象。

129、句查询数据库,一次获得所有的数据对象。句查询数据库,一次获得所有的数据对象。句查询数据库,一次获得所有的数据对象。2)2)把获得的所有数据对象根据把获得的所有数据对象根据把获得的所有数据对象根据把获得的所有数据对象根据IDID放入到第二级缓存中。放入到第二级缓存中。放入到第二级缓存中。放入到第二级缓存中。3)3)当当当当HibernateHibernate根据根据根据根据IDID访问数据对象的时候,首先从访问数据对象的时候,首先从访问数据对象的时候,首先从访问数据对象的时候,首先从SessionSession一级缓存中查;查不到,如果配置了二级缓一级缓存中查;查不到,如果配置了二级缓一级缓存中

130、查;查不到,如果配置了二级缓一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,存,那么从二级缓存中查;查不到,再查询数据库,存,那么从二级缓存中查;查不到,再查询数据库,存,那么从二级缓存中查;查不到,再查询数据库,把结果按照把结果按照把结果按照把结果按照IDID放入到缓存。放入到缓存。放入到缓存。放入到缓存。4)4)删除、更新、增加数据的时候,同时更新缓存。删除、更新、增加数据的时候,同时更新缓存。删除、更新、增加数据的时候,同时更新缓存。删除、更新、增加数据的时候,同时更新缓存。 95Hibernate的二级缓存(2)HibernateHibernate本

131、身并未提供二级缓存的产品化实现本身并未提供二级缓存的产品化实现本身并未提供二级缓存的产品化实现本身并未提供二级缓存的产品化实现( (只提供了一个基于只提供了一个基于只提供了一个基于只提供了一个基于HashTableHashTable的简单缓存以供调试的简单缓存以供调试的简单缓存以供调试的简单缓存以供调试) )。这里使用的是第三方缓存组件这里使用的是第三方缓存组件这里使用的是第三方缓存组件这里使用的是第三方缓存组件:EHcache.Hibernate:EHcache.Hibernate的二级缓存实现需的二级缓存实现需的二级缓存实现需的二级缓存实现需要进行以下配置要进行以下配置要进行以下配置要进行

132、以下配置(Hibernate3):(Hibernate3):首先在首先在首先在首先在hibernate.cfg.xmlhibernate.cfg.xml内添加内添加内添加内添加: :org.hibernate.cache.EhCacheProviderorg.hibernate.cache.EhCacheProvidertruetrue然后在映射文件中添加然后在映射文件中添加然后在映射文件中添加然后在映射文件中添加: :测试上面代码测试上面代码测试上面代码测试上面代码: :控制台输出多了这样一句控制台输出多了这样一句控制台输出多了这样一句控制台输出多了这样一句WARNWARN(CacheFac

133、tory.java:43)-read-onlycacheconfiguredformutable(CacheFactory.java:43)-read-onlycacheconfiguredformutableclass:hibernate.TUser,class:hibernate.TUser,二级缓存启用成功二级缓存启用成功二级缓存启用成功二级缓存启用成功!96Hibernate的二级缓存(3)javajava代码代码代码代码publicclassTestpublicclassTestpublicvoidexecuteQuery()publicvoidexecuteQuery()Listl

134、ist=newArrayList();Listlist=newArrayList();Sessionsession=HibernateSessionFactory.getSession();Sessionsession=HibernateSessionFactory.getSession();Queryquery=session.createQuery(“fromTUsert”);Queryquery=session.createQuery(“fromTUsert”);query.setCacheable(true);/query.setCacheable(true);/激活查询缓存激活查询缓

135、存激活查询缓存激活查询缓存list=query.list();list=query.list();session.close();session.close();publicvoidget()publicvoidget()Sessionsession=HibernateSessionFactory.getSession();Sessionsession=HibernateSessionFactory.getSession();TUsert=(TUser)session.get(hibernate.TUser,2);TUsert=(TUser)session.get(hibernate.TUse

136、r,2);System.out.println(t.getName();System.out.println(t.getName();session.close();session.close();测测测测 试试试试: :控制台只输出一条控制台只输出一条控制台只输出一条控制台只输出一条SQLSQL语句语句语句语句:Hibernate:selecttuser0_.idasid0_,:Hibernate:selecttuser0_.idasid0_,tuser0_.nameasname0_,tuser0_.sexassex0_fromtest.t_usertuser0_.nameasname0_,

137、tuser0_.sexassex0_fromtest.t_usertuser0_(tuser0_(即即即即Queryquery=session.createQuery(fromTUsert)Queryquery=session.createQuery(fromTUsert)这句代码这句代码这句代码这句代码所对应的所对应的所对应的所对应的SQL).executeQuery()SQL).executeQuery()方法与方法与方法与方法与get()get()方法使用的是不同的方法使用的是不同的方法使用的是不同的方法使用的是不同的Session!Session!可是可是可是可是executeQuer

138、y()executeQuery()方法与方法与方法与方法与get()get()方法只对数据库进行了一次操作方法只对数据库进行了一次操作方法只对数据库进行了一次操作方法只对数据库进行了一次操作, ,这就是二这就是二这就是二这就是二级缓存在起作用了级缓存在起作用了级缓存在起作用了级缓存在起作用了. . 97查询缓存概述 Hibernate的二级缓存策略是针对的二级缓存策略是针对ID查询的策略,和查询的策略,和对象对象ID密切相关,那么对于条件查询就不怎么适用了。对密切相关,那么对于条件查询就不怎么适用了。对于这种情况的存在,于这种情况的存在,Hibernate引入了引入了“查询缓存查询缓存”,在,

139、在一定程度上缓解这个问题。一定程度上缓解这个问题。启用查询缓存后,第一次执行查询时,启用查询缓存后,第一次执行查询时,Hibernate会会把查询结果放入查询缓存中。以后再次执行该查询语句时,把查询结果放入查询缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。只需从缓存中获得查询结果,从而提高查询性能。查询缓存依赖二级缓存。查询缓存依赖二级缓存。98启用查询缓存 对查询语句启用查询缓存的步骤对查询语句启用查询缓存的步骤1、启用二级缓存、启用二级缓存hibernate.cache.use_query_cache=true3、调用、调用Query接口的接口的setCac

140、heable(true)2、在配置文件中设置查询缓存属性为、在配置文件中设置查询缓存属性为true hibernate.cache.use_second_level_cache=true Query query = session.createQuery(hql); query.setCacheable(true); /启用查询缓存 query.setCacheRegion(“queryCacheRegion”); /设置查询缓存区域(数据过期策略) query.list();99查询缓存小结(2) 我们从查询缓存的策略中可以看出,我们从查询缓存的策略中可以看出,QueryCache只是在特定

141、的只是在特定的条件下才会发挥作用,而且要求相当严格:条件下才会发挥作用,而且要求相当严格:(1)完全相同的完全相同的HQL重复执行。重复执行。(2)重复执行期间,重复执行期间,QueryCache对应的数据表不能有数据变动(比对应的数据表不能有数据变动(比如添、删、改操作)如添、删、改操作)绝大多数的查询并不能从查询缓存中受益,所以绝大多数的查询并不能从查询缓存中受益,所以Hibernate默认默认是不进行查询缓存的。是不进行查询缓存的。查询缓存适用于以下场合:查询缓存适用于以下场合:(1)在应用程序运行时经常使用的查询语句(参数相同)在应用程序运行时经常使用的查询语句(参数相同)(2)很少对

142、与查询语句检索到的数据进行插入、删除或更新操作)很少对与查询语句检索到的数据进行插入、删除或更新操作100缓存使用缓存的条件使用缓存的条件1.读取大于修改。读取大于修改。2.数据量不能超过内存容量。数据量不能超过内存容量。3.对数据要有独享的控制。对数据要有独享的控制。4.可以容忍出现无效数据。可以容忍出现无效数据。101Hibernate高级功能高级功能Hibernate批量处理批量处理1.批量插入批量插入(1)通过Hibernate的缓存进行批量插入使用这种方法时,首先要在Hibernate的配置文件hibernate.cfg.xml中设置批量尺寸属性hibernate.jdbc.batc

143、h_size,且最好关闭Hibernate的二级缓存以提高效率。例如:50/设置批量尺寸设置批量尺寸false/关闭二级缓存关闭二级缓存102Hibernate批量处理批量处理下面以课程进行批量插入为例,说明批量插入操作的具体过程,这里假设批量插入500个课程到数据中:Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();for(inti=0;i500;i+)Kcbkcb=newKcb();/这里设置课程号为这里设置课程号为i,在实际应用中应该是被插入的课程对象,

144、在实际应用中应该是被插入的课程对象/已经放在集合或数组中,这里只要取出已经放在集合或数组中,这里只要取出kcb.setKch(i+);session.save(kcb);if(i%50=0)/以以50个课程为一个批次向数据库提交,此值应与配置的批量尺寸一致个课程为一个批次向数据库提交,此值应与配置的批量尺寸一致session.flush();/将该批量数据立即插入数据库中将该批量数据立即插入数据库中session.clear();/清空缓存区,释放内存供下批数据使用清空缓存区,释放内存供下批数据使用mit();HibernateSessionFactory.closeSession();103

145、Hibernate批量处理批量处理(2)绕过Hibernate直接调用JDBC进行插入由于Hibernate只是对JDBC进行了轻量级的封装,因此完全可以绕过Hibernate直接调用JDBC进行批量插入。因此上例可以改成如下代码:Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Connectionconn=session.connection();tryPreparedStatementstmt=conn.prepareStatement(insertin

146、toKCB(KCH)values(?);for(inti=0;i500;i+)stmt.setString(1,i+);stmt.addBatch();/添加到批处理命令中添加到批处理命令中stmt.executeBatch();/执行批处理任务执行批处理任务catch(SQLExceptione)e.printStackTrace();mit();HibernateSessionFactory.closeSession();104Hibernate批量处理批量处理2.批量更新批量更新(1)由Hibernate直接进行批量更新为了使Hibernate的HQL直接支持update/delete的

147、批量更新语法,首先要在Hibernate的配置文件hibernate.cfg.xml中设置HQL/SQL查询翻译器属性hibernate.query.factory_class。org.hibernate.hql.ast.ASTQueryTranslatorFactory105Hibernate批量处理批量处理下面使用HQL批量更新把课程表中的XS修改为30。由于这里是用Hibernate操作,故HQL要用类对象及其属性。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransact

148、ion();/在在HQL查询中使用查询中使用update进行批量更新进行批量更新Queryquery=session.createQuery(updateKcbsetxs=30);query.executeUpdate();mit();HibernateSessionFactory.closeSession();106Hibernate批量处理批量处理(2)绕过Hibernate调用JDBC进行批量更新由于这里是直接操作数据库,故要操作对应表,而不是类。Sessionsession=HibernateSessionFactory.getSession();Transactionts=sessi

149、on.beginTransaction();Connectionconn=session.connection();tryStatementstmt=conn.createStatement();/调用调用JDBC的的update进行批量更新进行批量更新stmt.executeUpdate(updateKCBsetXS=30);catch(SQLExceptione)e.printStackTrace();mit();HibernateSessionFactory.closeSession();107Hibernate批量处理批量处理3.批量删除批量删除(1)由Hibernate直接进行批量删

150、除与批量更新一样,为了使Hibernate的HQL直接支持update/delete的批量删除语法,首先要在Hibernate的配置文件hibernate.cfg.xml中设置HQL/SQL查询翻译器属性hibernate.query.factory_class。org.hibernate.hql.ast.ASTQueryTranslatorFactory108Hibernate批量处理批量处理下面将使用HQL批量删除课程表中课程号大于200的课程。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session

151、.beginTransaction();/在在HQL查询中使用查询中使用delete进行批量删除进行批量删除Queryquery=session.createQuery(deleteKcbwherekch200);query.executeUpdate();mit();HibernateSessionFactory.closeSession();109Hibernate批量处理批量处理(2)绕过Hibernate调用JDBC进行批量删除同样删除课程表中课程号大于200的课程。Sessionsession=HibernateSessionFactory.getSession();Transact

152、ionts=session.beginTransaction();Connectionconn=session.connection();tryStatementstmt=conn.createStatement();/调用调用JDBC的的delete进行批量删除进行批量删除stmt.executeUpdate(deletefromKCBwhereKCH200);catch(SQLExceptione)/TODOAuto-generatedcatchblocke.printStackTrace();mit();HibernateSessionFactory.closeSession();110

153、Hibernate事务管理事务管理1基于基于JDBC的事务管理的事务管理Hibernate是JDBC的轻量级封装,本身并不具备事务管理能力。在事务管理层,Hibernate将其委托给底层的JDBC或JTA,以实现事务管理和调度功能。在JDBC的数据库操作中,一项事务是由一条或多条表达式组成的不可分割的工作单元,通过提交commit()或回滚rollback()来结束事务的操作。将事务管理委托给JDBC进行处理是最简单的实现方式,Hibernate对于JDBC事务的封装也比较简单。如下面的代码:Sessionsession=sessionFactory.openSession();Transac

154、tiontx=session.beginTransaction();session.save(room);mit();从从JDBC层面而言,上面的代码实际上对应着:层面而言,上面的代码实际上对应着:Connectioncn=getConnection;cn.setAutoCommit(false);/JDBC调用相关的调用相关的SQL语句语句mit();111Hibernate事务管理事务管理下面的代码不会对数据库产生任何效果:如果要使代码真正作用到数据库,必须显示地调用如果要使代码真正作用到数据库,必须显示地调用Transaction指令:指令:sessionsession=session.

155、Factory.openSession();session.save(room);session.close();Sessionsession=sessionFactory.openSession();Transactiontx=sessio.beginTransaction();session.save(room);mit();session.close();112Hibernate事务管理事务管理2基于基于JTA的事务管理概念的事务管理概念JTA(Java Transaction API)是由Java EE Transaction Manager去管理的事务。其最大的特点是调用UserTr

156、ansaction接口的begin、commit和rollback方法来完成事务范围的界定、事务的提交和回滚。JTA可以实现统一事务对应不同的数据库。JTA主要用于分布式的多个数据源的两阶段提交的事务,而JDBC的Connection提供单个数据源的事务。后者因为只涉及一个数据源,所以其事务可以由数据库自己单独实现。而JTA事务因为其分布式和多数据源的特性,不可能由任何一个数据源实现事务。因此,JTA中的事务是由“事务管理器”实现的。它会在多个数据源之间统筹事务,具体使用的技术就是所谓的“两阶段提交”。113JTATransactionJTATransaction可以简单的理解成跨数据库的事物

157、,由应用JTA 容器实现;使用JTATransaction需要配置hibernate.transaction.factory_class参数,该参数缺省值是org.hibernate.transaction. JDBCTransactionFactory,当使用JTATransaction时需要将该参数改成org.hibernate.transaction.JTATransactionFactory,并配置jta.UserTransaction参数JNDI名(Hibernate在启动JTATransaction时要用该值到JNDI的上下文Context中去找javax.transaction.

158、UserTransaction)。javax.transaction.UserTransactin tx =context.lookup(“jndiName”);trytx.begin();/多个数据库的session操作;/session1./mit();catch(Exception e)tx.rollback(); throw e;1143 3锁锁锁锁业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算处理中,希望对某个结算时间点的数据进行处理,而不希望在结算过程中(可能是几秒,也可能是几个小时),数据再发生变化。此时,需要通过一些机制来保证这些数据在某个操作过程中

159、不会被外界修改,这样的机制就是所谓的“锁”,即给选定的目标数据上锁,使其无法被其他程序修改。Hibernate支持两种锁机制,悲观锁(Pessimistic Locking)和乐观锁(Optimistic Locking)。115Hibernate不适合的场景不适合不适合OLAP(On-LineAnalyticalProcessing联机分析处理联机分析处理),以查询分析数据为主的系统;,以查询分析数据为主的系统;适合适合OLTP(on-linetransactionprocessing联联机事务处理)。机事务处理)。对于些关系模型设计不合理的老系统,也不能发对于些关系模型设计不合理的老系统,

160、也不能发挥挥hibernate优势。优势。数据量巨大,性能要求苛刻的系统,数据量巨大,性能要求苛刻的系统,hibernate也很难达到要求也很难达到要求,批量操作数据的效率也不高。批量操作数据的效率也不高。 116Hibernate最佳实践(Best Practices)SessionFactorySessionFactory的创建非常消耗资源,整个应用的创建非常消耗资源,整个应用的创建非常消耗资源,整个应用的创建非常消耗资源,整个应用一般只要一个一般只要一个一般只要一个一般只要一个SessionFactorySessionFactory就够了,只有多就够了,只有多就够了,只有多就够了,只有多

161、个数据库的时候才会使用多个个数据库的时候才会使用多个个数据库的时候才会使用多个个数据库的时候才会使用多个SessionFactorySessionFactory。1172 2、在整个应用中,、在整个应用中,、在整个应用中,、在整个应用中,SessionSession和事务应该能够统一和事务应该能够统一和事务应该能够统一和事务应该能够统一管理。(管理。(管理。(管理。(SpringSpring为为为为HibernateHibernate提供了非常好的支提供了非常好的支提供了非常好的支提供了非常好的支持)持)持)持)3 3、将所有的集合属性配置设置为懒加载、将所有的集合属性配置设置为懒加载、将所有

162、的集合属性配置设置为懒加载、将所有的集合属性配置设置为懒加载(lazy=”true”lazy=”true”)。)。)。)。在在在在hibernate2.xhibernate2.x版本中,版本中,版本中,版本中,lazylazy默认值是默认值是默认值是默认值是“ “false”,false”,但但但但hibernate3.xhibernate3.x已经将已经将已经将已经将lazylazy的默认改为的默认改为的默认改为的默认改为“ “true”true”了。了。了。了。118Hibernate最佳实践(Best Practices)4 4、在定义关联关系时,集合首选、在定义关联关系时,集合首选、在

163、定义关联关系时,集合首选、在定义关联关系时,集合首选SetSet,如果集合中的如果集合中的如果集合中的如果集合中的实体存在重复,则选择实体存在重复,则选择实体存在重复,则选择实体存在重复,则选择ListList(在定义配置文件时,可在定义配置文件时,可在定义配置文件时,可在定义配置文件时,可以将以将以将以将ListList定义为定义为定义为定义为bagbag),),),),数组的性能最差。数组的性能最差。数组的性能最差。数组的性能最差。5 5、在一对多的双向关联中,一般将集合的、在一对多的双向关联中,一般将集合的、在一对多的双向关联中,一般将集合的、在一对多的双向关联中,一般将集合的inver

164、seinverse属属属属性设置为性设置为性设置为性设置为truetrue,让集合的对方维护关联关系。例如:让集合的对方维护关联关系。例如:让集合的对方维护关联关系。例如:让集合的对方维护关联关系。例如:Group-UserGroup-User,由由由由UserUser来维护来维护来维护来维护GroupGroup和和和和UserUser的关联关的关联关的关联关的关联关系。系。系。系。6 6、HQLHQL子句本身大小写无关,但是其中出现的类名和子句本身大小写无关,但是其中出现的类名和子句本身大小写无关,但是其中出现的类名和子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。属性名必须注意大小写区分。属性名必须注意大小写区分。属性名必须注意大小写区分。7 7、如果要精通、如果要精通、如果要精通、如果要精通HibernateHibernate,熟练掌握关系数据库理论熟练掌握关系数据库理论熟练掌握关系数据库理论熟练掌握关系数据库理论和和和和SQLSQL是前提条件。是前提条件。是前提条件。是前提条件。119

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号