• 1. Hibernate入门案例Hibernate关系数据库Customer类BusinessService类对象关系型映射Hibernate APIHibernate配置文件Customers表北京传智播客教育 www.itcast.cn
  • 2. Hibernate入门创建配置文件hibernate.dialect=net.sf.hibernate.dialect.OracleDialect hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver hibernate.connection.url=jdbc:oracle:thin:peopres/peopres@127.0.0.1:1521:oracle9 hibernate.connection.username=peopres hibernate.connection.password=peopres hibernate.show_sql=true北京传智播客教育 www.itcast.cn
  • 3. Hibernate入门创建持久化类public class Customer implements Serializable { private static final long serialVersionUID = 5431991012351413505L; private Long id; private String name; private String email; ……北京传智播客教育 www.itcast.cn
  • 4. Hibernate入门 创建数据库drop database if exists SAMPLEDB; create database SAMPLEDB; use SAMPLEDB; create table CUSTOMERS ( ID bigint not null primary key, NAME varchar(15) not null, EMAIL varchar(128) not null, PASSWORD varchar(8) not null, PHONE int , ADDRESS varchar(255), SEX char(1) , IS_MARRIED bit, DESCRIPTION text, IMAGE blob, BIRTHDAY date, REGISTERED_TIME timestamp );北京传智播客教育 www.itcast.cn
  • 5. Hibernate入门创建对象-关系映射文件 …… 北京传智播客教育 www.itcast.cn
  • 6. Hibernate入门把customer持久化类映射到customers表:类和表的映射 :持久化类的OID和表主键映射 北京传智播客教育 www.itcast.cn
  • 7. Hibernate入门java、hibernate、sql类型对应关系Customer类属性javahibernateCutomers字段名Sql类型Namejava.lang.StringstringNAMEVarchar(15)PhoneintintPHONEINTSexcharcharacterSEXCHAR(1)MarriedbooleanbooleanIS_MARRIEDBITDescriptionjava.lang.StringtextDESCRIPTIONCLOBimagebyte[]binaryIMAGEBLOBbirthdayjava.sql.DatedateBIRTHDAYDATEregisteredTimejava.sql.TimeStamptimestampREGISTERED_TIMETIMESTAMP北京传智播客教育 www.itcast.cn
  • 8. Hibernate入门通过API操作数据库北京传智播客教育 www.itcast.cn
  • 9. Hibernate入门通过API操作数据库北京传智播客教育 www.itcast.cn
  • 10. Hibernate入门Hibernate初始化1、创建configuration对象,把hibernate.properties文件读入内存。 2、add(……)把映射文件读入内存 3、buildSessionFactory()数据源。重量级对象。北京传智播客教育 www.itcast.cn
  • 11. Hibernate入门Hibernate初始化 访问Session接口save() update() delete() load() find()北京传智播客教育 www.itcast.cn
  • 12. Hibernate入门北京传智播客教育 www.itcast.cn
  • 13. Java对象持久化概述Hibernate是什么 连接java应用程序和关系型数据库的中间件 对JDBC API封装,负责对象持久化 位于持久化层,封装所有的数据访问细节,使业务逻辑层更关注于业务逻辑。 一种ORM映射工具。北京传智播客教育 www.itcast.cn
  • 14. Java对象持久化概述应用程序的分层体系结构数据库应用程序层数据库表述层业务逻辑程序层双层体系结构三层体系结构表述层:提供与用户交互的GUI。 业务逻辑层:实现各种业务逻辑。 数据库层:负责存放和管理应用的持久性数据。北京传智播客教育 www.itcast.cn
  • 15. Java对象持久化概述应用程序的分层体系结构 Java应用的持久化层表述层业务逻辑层数据库层表述层业务逻辑层持久化层数据库层北京传智播客教育 www.itcast.cn
  • 16. Java对象持久化概述Hibernate中间件特性应用1业务逻辑层应用2业务逻辑层应用3业务逻辑层持久化层 (hibernate)数据库1数据库2数据库3持久化层封装了数据访问的细节,为业务逻辑层提供了面向对象的API。完善的持久化层应该 达到的目标: 1.代码重用性高,可完成所有的数据访问操作。 2.如果需要的话,能够支持多种数据库平台。 3.具有相对独立性,当持久化层变化时,不会影响上层实现。北京传智播客教育 www.itcast.cn
  • 17. Java对象持久化概述软件模型 概念模型:模拟问题域中的真实实体。描述每个实体的概念和属性及实体间关系。不描述实体行为。实体间的关系有一对一、一对多和多对多。客户 Name age 订单 orderNumber price 1*北京传智播客教育 www.itcast.cn
  • 18. Java对象持久化概述软件模型 关系数据模型:在概念模型的基础上建立起来的,用于描述这些关系数据的静态结构。有以下内容组成: 1.若干表 2.表的所有索引 3.视图 4.触发器 5.表与表之间的参照完整性Customers表 ID NAME AGEORDERS表 ID CustomerID Order_number price北京传智播客教育 www.itcast.cn
  • 19. Java对象持久化概述软件模型 域模型:在软件的分析阶段创建概念模型,在软件设计阶段创建域模型。 组成部分: 1.具有状态和行为的域对象。 2.域对象之间的关联。北京传智播客教育 www.itcast.cn
  • 20. Java对象持久化概述软件模型 域对象(domain object):构成域模型的基本元素就是域对象。对真实世界的实体的软件抽象,也叫做业务对象(Business Object(BO)).域对象可代表业务领域中的人、地点、事物或概念。 域对象分为以下几种: 实体域对象:通常是指业务领域中的名词。 (plain old java object)。 过程域对象:应用中的业务逻辑或流程。依赖 于实体域对象,业务领域中的动词。如 发出订单、登陆等。 事件域对象:应用中的一些事件(警告、异常)。北京传智播客教育 www.itcast.cn
  • 21. Java对象持久化概述软件模型 域对象间的关系 1.关联:类间的引用关系。以属性定义的方式表现。关联可分为一对一、一对多和多对多。还可分为单项关联和双向关联。OrderCustomer北京传智播客教育 www.itcast.cn
  • 22. Java对象持久化概述软件模型 域对象间的关系 依赖:类之间访问关系。无需定义成属性。在A中访问B中的 方法或属性,或者A负责实例化B。BusinessServiceCustomer北京传智播客教育 www.itcast.cn
  • 23. Java对象持久化概述软件模型 域对象间的关系 3.聚集(Aggregation):整体与部分的关系。例人与手的关系。部分类的对象不能单独存在,他的生命周期依赖于整体类的对象的生命周期,整体消失时,部分也随之消失。Person hand:setHand ……北京传智播客教育 www.itcast.cn
  • 24. Java对象持久化概述软件模型 域对象间的关系 4.一般化(Generalization):类之间继承关系。Employee nameHourEmployee rateSalaryEmployee salary北京传智播客教育 www.itcast.cn
  • 25. Java对象持久化概述内存Customer对象order对象数据库持久化重新加载到内存软件模型 域对象的持久化概念 实体域对象在内存中创建后,不能永久存在。将实体域对象永久保存起来,就是持久化的过程。通常只有实体域对象需要持久化,过程域对象和事件域对象一般不需要持久化。广义持久化指增、删、改、查。北京传智播客教育 www.itcast.cn
  • 26. Java对象持久化概述ORM简介 对象-关系映射(ORM,即Object-Relation Mapping). 指单个组件中负责所有实体域对象的持久化,封装数据访问细节。域模型 (对象、属性、关联、继承和多态)ORM API ORM 实现关系数据模型 (表、字段、索引、主键和外键)业务逻辑层对象-关系映射文件 (xml)持久化层数据库层参照ORM 充当业务逻辑层和数据库层之间的桥梁北京传智播客教育 www.itcast.cn
  • 27. Java对象持久化概述ORM简介 对象-关系映射的概念面向对象概念面向关系概念类表对象表的行(记录)属性表的列(字段)域模型Address类 Province city street zipcodeCustomer类 id name homeAddress comAddress关系数据模型Customer类 ID …… HOME_PROVINCE HOME_CITY …… COM_PROVINCE COM_CITY ……注:域模型中类的数目要比关系数据模型中 表的数目多。北京传智播客教育 www.itcast.cn
  • 28. Java对象持久化概述ORM简介 ORM中间件的使用方法 采用元数据来描述对象-关系映射细节,元数据通常采用xml格式,并存放在专门的对象-关系映射文件中。只要配置了持久化类与表的映射关系,orm中间件在运行时就能够参照映射文件的信息,把域对象持久化到数据库中。public void deleteCustomer(Customer c){ Session session = getSession(); session.delete(c); } 执行步骤如下: 1.运用反射机制,获得Customer对象的Customer.class类。 2.参照映射文件得到Customer类对应的表的信息,以及和Customer类关联的类以及 相应的表信息。 3.根据以上信息生成SQL语句。 4.调用hibernate API,执行该语句。北京传智播客教育 www.itcast.cn
  • 29. Java对象持久化概述Hibernate API简介Hibernate对JDBC做了轻量级的封装。所谓轻量级是 指Hibernate并没有完全封装JDBC,java应用既可以 通过HibernateAPI来访问数据库,还可直接通过JDBC API访问数据库。北京传智播客教育 www.itcast.cn
  • 30. Java对象持久化概述Hibernate API简介 Hibernate核心接口 1.Configuration 配置hibernate,根启动hibernate,创建 sessionFactory对象。 2.SessionFactory 初始化hibernate,充当数据源代理,创建 session对象。线程安全的,可被多个线程共享。重量级的, 需要一个很大的缓存,用于存放于定义的sql语句和映射元数 据等。用户还可为它配置一个缓存插件,称为二级缓存。 3.Session 使用最广泛,也被称为持久化管理器,它提供和持久 化相关的操作。增、删、改、查等。不是线程安全的,避免多 个线程共享。轻量级的,创建和销毁不需要消耗太多资源。 Session中有一个缓存,称为一级缓存。存放当前工作单元加 载的对象。北京传智播客教育 www.itcast.cn
  • 31. Java对象持久化概述Hibernate API简介 Hibernate核心接口(续) 4.Transaction hibernate数据库事务接口, 它对底层的事务接口作了封装.底层事务接 口包括: JDBC API JTA(java Transaction API) CORBA(common object request Broker architecture)北京传智播客教育 www.itcast.cn
  • 32. Java对象持久化概述Hibernate API简介 Hibernate核心接口(续) 5.Query和Criteria接口:都是查询接口,query实例 包装了HQL查询语句,hql是面向对象的,他引用类 名及类的属性名,而不是表名和字段名。Criteria接 口完全封装了基于字符串形式的查询语句,比 query接口更面向对象,他擅长执行动态查询。 sessoin接口的find方法也具有数据查询功能,但他 只是执行一些简单的hql查询语句的快捷方式,远没 有query接口功能强大。北京传智播客教育 www.itcast.cn
  • 33. Java对象持久化概述Hibernate API简介 Hibernate映射类型接口 1.PrivateType类:映射java基本数据类型,包括 ByteType、ShortType、IntegerType、 LongType、FloatType、DoubleType、 CharactorType、BooleanType。 2.DateType:映射java日期类型。 3.BinaryType:映射Byte[]类型。Query.setParameter(“name”,”name”,Hibernate.STRING)北京传智播客教育 www.itcast.cn
  • 34. Java对象持久化概述Hibernate API简介 可供扩展的接口 hibernate提供的多数功能是可配置的,允许用户选择适当的内置策略。如可配置如下数据库方言: hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect hibernate.dialect=net.sf.hibernate.dialect.OracleDialect hibernate.dialect=net.sf.hibernate.dialect.SybaseDialect北京传智播客教育 www.itcast.cn
  • 35. Java对象持久化概述Hibernate API简介 可供扩展的接口 如果hibernate内置的策略不能满足需求时,允许用户自定义实现接口或扩展特定的类。Hibernate的扩展点包括: 主键生成策略:IdentifierGenerator sql方言:Dialect抽象类 缓存机制:cache和cacheprovider接口 jdbc连接管理器:connectionprovider等北京传智播客教育 www.itcast.cn
  • 36. Java对象持久化概述小结表现层业务逻辑层持久化层(orm中间件、负责封装数据访问细节)数据库层实体域对象 (业务数据)过程域对象 (业务逻辑)北京传智播客教育 www.itcast.cn
  • 37. 对象-关系映射基础本章解决的问题 1.持久化类没有getXXX和setXXX方法。 2.持久化类的属性在库中没有对应的字段,或 字段没有对应的属性 3.控制hibernate的insert、update语句。 4.设置从持久化类映射到数据库表,以及持久 化类的属性映射到数据库表的字段的命名策 略。北京传智播客教育 www.itcast.cn
  • 38. 对象-关系映射基础持久化类的属性及访问方法 Hibernate中持久化类的访问者有两个: 1.Java应用程序 2.hibernate(何时调用get、set方法?)Customer对象getXXX()方法setXXX()方法hibernateJava 应用程序用户 界面数据库Java应用程序不能访问持久化类的private方法,而hibernate没有这 个限制,它可以访问各种级别的方法。北京传智播客教育 www.itcast.cn
  • 39. 对象-关系映射基础持久化类的属性及访问方法 基本数据类型和包装类型 基本数据类型和包装类型对应的hibernate映射 类型相同。基本类型可直接运算、无法表达null、数字类型的默认值为0。 包装类默认值是null。当对于默认值有业务意义的时候需要使用包装类。北京传智播客教育 www.itcast.cn
  • 40. 对象-关系映射基础持久化类的属性及访问方法 Hibernate访问持久化类属性的策略 1.propertye 默认值:表明hibernate通过getXXX和 setXXX来访问类属性。推荐使用。提高域模型透明性。 2.field:hibernate通过java反射机制直接访问类属性。对于没有 javabean方法的属性可设置该访问策略。除了设置property属性的access为field和property之外 还可以自定义访问策略,需要创建实现net.sf.hibernate. property.PropertyAccessor接口的类。北京传智播客教育 www.itcast.cn
  • 41. 对象-关系映射基础持久化类的属性及访问方法 在持久化类的方法中加入程序逻辑class Customer{ ….. private String firstname ; private String lastname ; public String getName(){ return firstname + “ ” + lastname ; } public void setName(String name){ StringTokenizer t = new StringTokenizer(name); firstname = t.nextToken(); lastname = t.nextToken(); } } 北京传智播客教育 www.itcast.cn
  • 42. 对象-关系映射基础持久化类的属性及访问方法 在持久化类的方法中加入程序逻辑 在customer.hbm.xml文件中无需映射firstname和lastname属 性,而是映射name属性。尽管类中并没有name属性,由于hibernate不是直接访问 Name属性,而是调用get、set方法,因此建立了 Firstname、Lastname和表之间的联系。Hibernate getName() setName()CUSTOMERS表Name字段Customer类firstname lastname北京传智播客教育 www.itcast.cn
  • 43. 对象-关系映射基础持久化类的属性及访问方法 在持久化类的方法中加入程序逻辑 不管在类中是否存在name属性,只要在Customer.hbm.xml文件中映射了name属性,在hql语句中就能访问他。Session.find(“from customer as c where c.name=‘tom’”)如果改成: 后过如何?北京传智播客教育 www.itcast.cn
  • 44. 对象-关系映射基础持久化类的属性及访问方法 设置派生属性 利用元素的formula属性,用来设置一个sql表达式,hibernate将根据它来计算出派生属性的值。北京传智播客教育 www.itcast.cn
  • 45. 对象-关系映射基础持久化类的属性及访问方法 控制insert、update语句映射属性作用 insert属性若为false,在insert语句中不包含该字段,该字段永远不能被插入。默认值true。 update属性若为false,update语句不包含该字段,该字段永远不能被更新。默认值为true。 mutable属性若为false,等价于所有的元素的update属性为false,整个实例不能被更新。默认为true。 dynamic-insert属性若为true,等价于所有的元素的dynamic-insert为true,保存一个对象时,动态生成insert语句,语句中仅包含取值不为null的字段。默认false。 dynamic-update属性若为true,等价于所有的元素的dynamic-update为true,更新一个对象时,动态生成update语句,语句中仅包含取值不为null的字段。默认false。北京传智播客教育 www.itcast.cn
  • 46. 对象-关系映射基础处理sql引用表示符 在SQL语法中,表示符是指用于为数据库表、视图、字段或索引等名字的字符串,常规表示符不包括空格,也不包含特殊字符,因此无需使用引用符号。如果数据库表名或列名包含特殊字符,可以使用引用表示符。北京传智播客教育 www.itcast.cn
  • 47. 对象-关系映射基础设置类的包名 如果在一个映射文件中包含多个类,并且这些类位于同一个包中,可以设置元素的package属性,避免为每个类提供完整的类名。 …… …… …… …… 北京传智播客教育 www.itcast.cn
  • 48. 映射对象标识符Java按地址区分同一个类的不同对象. 关系数据库用主键区分同一条记录. Hibernate使用OID来建立内存中的对象和数据库中记录的对应关 系。对象的OID和数据库的表的主键对应。为保证OID的唯一性,应 该让Hibernate来为OID付值。北京传智播客教育 www.itcast.cn
  • 49. 映射对象表示符关系数据库按主键区分不同记录 主键必备条件: 1. 不允许null 2.唯一,不重复 3.之永远不会改变 自然主键:把具有业务含义的字段作为主键叫做自然主 键。北京传智播客教育 www.itcast.cn
  • 50. 映射对象表示符关系数据库按主键区分不同记录 把主键定义为自动增长类型 在my SQL中,把字段设为auto_increment类型,数据库会自 动为主键付值。 在ms SQL server中,把字段设为identity类型,数据库会自 动为主键付值。 从序列(sequence)中获取自动增长的描述符 create sequence seq_customer increment by 2 start with 1 insert into customers values(seq_customer.curval,’..’) 北京传智播客教育 www.itcast.cn
  • 51. 映射对象表示符Java语言按内存地址区分不同的对象 ==和equal()方法。北京传智播客教育 www.itcast.cn
  • 52. 映射对象表示符Hibernate中用对象表示符(OID)来区分对象 OID是关系数据库中的主键在java对象模型中的等价物。在运行时,hibernate根据OID来维持java对象和数据库记录的对应关系。Customer c1 = (Customer)session.load(Customer.class,new Long(1)); Customer c2 = (Customer)session.load(Customer.class,new Long(1)); Customer c3 = (Customer)session.load(Customer.class,new Long(3)); c1 == c2 ? c1 == c3 ? 子元素用来设定表示符生成器。Hibernate提供了表识符生成器接 口:net.sf.hibernate.id.IdentifierGenerator,并提供了多种内置的实现。北京传智播客教育 www.itcast.cn
  • 53. 映射对象表示符表示符生成器描述increment适用于代理主键。由hibernate自动以递增的方式生成表识符,每次增量为1identity适用于代理主键。由底层数据库生成表识符。条件是数据库支持自动增长数据类型。sequence适用于代理主键。Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。hilo适用于代理主键。Hibernate根据hign/low算法生成标识符。Hibernate把特定表的字段作为“hign”值。默认情况下,采用hibernate_unique_key表的next_hi字段。native适用于代理主键。根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilouuid.hex适用于代理主键。Hibernate采用128位的UUID算法来生成标识符。该算法 能够在网络环境中生成唯一的字符串标识符,这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间。assigned适用于自然主键。由java程序负责生成标识符。不能把setID()方法声明为 Private的。尽量避免使用自然主键。北京传智播客教育 www.itcast.cn
  • 54. 映射对象表示符Hibernate内置标识符用法 incrementselect max(id) from table; 适用范围: 1。由于不依赖与底层数据库,适合所有的数据库系统。 2。单个进程访问同一个数据库的场合,集群环境下不推荐适用。 3。OID必须为long、int或short类型,如果把OID定义为byte类型,抛异常。北京传智播客教育 www.itcast.cn
  • 55. 映射对象表示符Hibernate内置标识符用法 Identity 由底层数据库生成标识符.需要把字段定义成自增型。 my sql 中为auto_increment ms sql server中为identity 北京传智播客教育 www.itcast.cn
  • 56. 映射对象表示符Hibernate内置标识符用法 sequence tester_id_seq 适用范围: 地层数据库要支持序列。Oracle DB2 SAP等。 OID必须为long、int或shot类型。 北京传智播客教育 www.itcast.cn
  • 57. 映射对象表示符Hibernate内置标识符用法 hilo hi_value next_value 100 使用范围: 该机制不依赖于地层数据库,因此适用于所有的数据库系统。 OID必须为long、int、short类型,如果为byte类型的话,会抛出异常。 Net.sf.hibernate.id.IdentifierGeneratorException:this id generator generates Long、integer、short。北京传智播客教育 www.itcast.cn
  • 58. 映射对象表示符Hibernate内置标识符用法 native 适用范围: 该类型能根据地层数据库系统的类型,自动选择合适的标识符生成器,因此很适合于跨数据 库的平台,即在同一个应用中需要连接多种数据库系统的场合。 OID与以上类同。北京传智播客教育 www.itcast.cn
  • 59. 映射对象表示符映射自然主键 映射单个自然主键 北京传智播客教育 www.itcast.cn
  • 60. 映射对象表示符映射自然主键 映射复合主键 使用联合主键的持久化类需要实现serializable接口和覆盖equals()、hashCode()方法。可以使用customId属性来设置连联合主键 北京传智播客教育 www.itcast.cn
  • 61. 映射一对多关联关系Order到Customer的多对一单向关联Customer 到Order的一对多单向关联Customer 到Order的一对多双向关联北京传智播客教育 www.itcast.cn
  • 62. 映射一对多关联关系建立多对一的单向关联关系北京传智播客教育 www.itcast.cn
  • 63. 映射一对多关联关系many-to-one属性: name:设定待映射的持久化类的名字。 column:设定和持久化类的属性对应的表的外键。 class:设定持久化类的属性的类型。 not-null:是否允许为空。建立多对一的单向关联关系(续)北京传智播客教育 www.itcast.cn
  • 64. 映射一对多关联关系tx = session.beginTransaction(); Customer c = new Customer(); c.setName("TOM"); session.save(c); Order o1 = new Order(); o1.setOrderNumber("1"); o1.setCustomer(c); Order o2 = new Order(); o2.setOrderNumber("1"); o2.setCustomer(c); session.save(o1); session.save(o2); tx.commit();北京传智播客教育 www.itcast.cn
  • 65. 映射一对多关联关系建立多对一的单向关联关系 tx = session.beginTransaction(); Customer c = new Customer(); c.setName("TOM"); //session.save(c); ?会有什么后果 Order o1 = new Order(); o1.setOrderNumber("1"); o1.setCustomer(c); Order o2 = new Order(); o2.setOrderNumber("1"); o2.setCustomer(c); session.save(o1); session.save(o2); tx.commit();北京传智播客教育 www.itcast.cn
  • 66. 映射一对多关联关系建立多对一的单向关联关系 级联保存和更新 当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。 ?北京传智播客教育 www.itcast.cn
  • 67. 映射一对多关联关系映射一对多双向关联关系Class Customer{ … public Set orders = new Set(); public Set getOrders(){ return orders; } public void setOrders(Set orders){ this.orders = orders; } … } 北京传智播客教育 www.itcast.cn
  • 68. 映射一对多关联关系映射一对多双向关联关系(续) Hibernate要求在持久化类中定义集合属性时,必须把属性声明为接口类型,如Set、Map、List.声明为接口类型可提高持久化类的透明性,当hibernate调用setOrders()方法时,传递的参数是Hibernate自定义的实现该接口类的实例。如果定义成类(如HashSet)型,强迫hibernate把该类型的实例传给他。 通常在定义集合属性时,直接初始化为一个实现类的实例。 private Set orders = new HashSet(); 可避免空指针异常。北京传智播客教育 www.itcast.cn
  • 69. 映射一对多关联关系映射一对多双向关联关系(续) name:设定待映射持久化类的属性名。 cascade:设定级联操作的程度。 key子属性:设定与所关联的持久化类对应的标 的外键。 one-to-many子属性:设定所关联的持久化类。北京传智播客教育 www.itcast.cn
  • 70. 映射一对多关联关系映射一对多双向关联关系 元素的inverse属性Customer c = (Customer)session .load(Customer.class,new Long(2)); Order o = (Order)session.load(Order.class,new Long(2)); o.setCustomer(c); c.getOrders().add(o); tx.commit(); ------------------------------------------------------- Update orders set …... Update orders set …… hibernate执行两条更新语句。北京传智播客教育 www.itcast.cn
  • 71. 映射一对多关联关系映射一对多双向关联关系 元素的inverse属性(续)Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的改变 来同步更新数据库,因此执行了上述的两条更新语句。 重复执行多余的sql语句会影响java性能,解决这一问题的办法是把 元素的inverse属性设为true,该属性的默认值是false。 Customer和order的双向关联中,customer端的关联只是order端关联 的镜像。当hibernate同时探测到持久化对象customer和order的状态均 发生变化时,仅按照order对象状态更新数据库。北京传智播客教育 www.itcast.cn
  • 72. 映射一对多关联关系映射一对多双向关联关系 元素的inverse属性(续)Customer c = (Customer)session.load(…)); Order o = (Order)session.load(…); o.setCustomer(c); //c.getOrders().add(c); tx.commit(); ------------------------------------------------------ 以上代码仅设置了order对象的customer属性,hibernate仍然会按照 order对象的状态 的变化来同步更新数据库,执行以下sql语句: Update orders set order_number=‘…’,customer_id=2 where id = 2北京传智播客教育 www.itcast.cn
  • 73. 映射一对多关联关系映射一对多双向关联关系 元素的inverse属性(续)Customer c = (Customer)session.load(……); Order o = (Order)session.load(……); //o.setCustomer(c); c.getOrders().add(c); tx.commit(); ----------------------------------------------------- 以上代码仅设置了customer对象的orders属性,由于元素的 inverse属性为true,因此,hibernate不会按照customer对象的状态 变化来同步更新数据库。北京传智播客教育 www.itcast.cn
  • 74. 映射一对多关联关系映射一对多双向关联关系 元素的invers属性结论: 1.在映射一对多的双向关联关系时,应该在one方把inverse 属性设为true,这可以提高性能。 2.在建立两个对象的关联时,应该同时修改关联两端的相应 属性: Customer.getOrders().add(order); Order.setCustomer(customer); 这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务 逻辑层的程序代码不受Hibernate实现类的影响。同理,当删 除双向关联的关系时,也应该修改关联两端的对象的相应属性: Customer.getOrders().remove(order); Order.setCustomer(null);北京传智播客教育 www.itcast.cn
  • 75. 映射一对多关联关系映射一对多双向关联关系 级联删除Customer customer = (Customer) s.load(Customer.class,new Long(2)); Session.delete(customer); tx.commit(); ----------------------------------------------------------------- 如果cascade属性取默认值none,不会自动删除和customer关联的其他持久化对象。如 果希望删除customer时,自动删除和customer关联的order对象,可把cascade属性设 为delete。 再运行删除方法的时候,会自动删除order对象,此时hibernate执行如下语句: Delete from customer where customer_id = 1; Delete customer where id = 1;北京传智播客教育 www.itcast.cn
  • 76. 映射一对多关联关系映射一对多双向关联关系 父子关系Customer customer = (Customer)session.load(……); Order order = (Order)customer.getOrders().iterator().next(); //删除关联关系 customer.getOrders().remove(order); order.setCustomer(null); tx.commit(); -------------------------------------------------------------- 如果cascade为默认值none,hibernate会执行如下语句: Update orders set Customer_id = null where ID = 2; 如果希望程序自动删除不再和customer关联的order对象,可以把cascade属性设为 all-delete-orphan。 Delete from orders where CUSTOMER_ID = 2 and ID = 2北京传智播客教育 www.itcast.cn
  • 77. 映射一对多关联关系映射一对多双向关联关系 父子关系当customer.hbm.xml的元素的cascade属性取值为 all-delete-orphan,Hibernate会按照如下方式处理customer对象: 1.当保存或更新customer对象时,级联保存或更新所有关联的order 对象,相当于save-update. 2.当删除customer对象时,级联删除所有的order对象,相当于delete。 3.删除不再和customer对象关联的所有order对象。 当关联双方存在父子关系时,就可以把父方的cascade属性设为 all-delete-orphan. 所谓父子关系:是指父方来控制子方的持久化生命周期,子方对象必 须和一个父方对象关联。北京传智播客教育 www.itcast.cn
  • 78. 映射一对一关联关系映射一对一关联 按照外键映射CUSTOMERS表 --------------- ID<> NAME HOME_ADDRESS<>ADDRESSS表 --------------- ID<> CITY STREET PROVINCEcustomer.hbm.xml: address.hbm.xml one-to-one元素的property-ref属性为homeAddress,表明建立了从homeAddress对象到 Cusotmer对象的关联.北京传智播客教育 www.itcast.cn
  • 79. 映射一对一关联关系映射一对一关联(主键映射)CUSTOMERS表 --------------- ID NAME ADDRESSS表 --------------- ID CITY STREET PROVINCEcustomer.hbm.xml: address.hbm.xml one-to-one元素的constraint属性为true,表明Address表的ID主键同时作为外键参照 Customers表。在address.hbm.xml文件中,必须为OID使用foreign标识符生成策略。 customer 北京传智播客教育 www.itcast.cn
  • 80. 映射多对多关联关系映射单向多对多关联TEACHERS表 ---------------- ID NAMELINKS表 ---------------- TID SIDSTUDENTS表 ---------------- ID STUNOTeacher.hbm.xml Student.hbm.xml 北京传智播客教育 www.itcast.cn
  • 81. 操纵持久化对象Session接口提供增、删、改、查功能。 Session中有一个缓存,位于缓存中对象处 于持久化状态,他和数据库中的记录相对 应。Session能够在某些时间点,按照缓存 中的持久化对象的属性变化来同步更新数据 库,这一过程被称为清理缓存。除了持久化 状态还有游离态和临时态。北京传智播客教育 www.itcast.cn
  • 82. 操纵持久化对象Java对象在JVM中的生命周期Customer c = new Customer(“TOM”,new HashSet()); Order o1 = new Order(“Tom_order001”,null); Order o2 = new Order(“Tom_order002”,null); o1.setCustomer(c); c.getOrders().add(o1); o1 = null; o2 = null; c = null;北京传智播客教育 www.itcast.cn
  • 83. 操纵持久化对象理解session的缓存 当session的save()方法持久化一个对象 时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。北京传智播客教育 www.itcast.cn
  • 84. 操纵持久化对象理解session的缓存(续)Customer c = new Customer(“TOM”,new HashSet()); session.save(c); Long id = c.getId(); c = null; Customer c2 = (Customer)session.load(Customer.class,id); tx.commit(); session.close(); c2.getName(); C2 = null; --------------------------------------------------------------------------------------------- 缓存的作用: 1。减少访问数据库的频率。 2。保证缓存中的对象与数据库中的相关记录保持同步。 3。当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循 还,以及由死循环引起的JVM堆栈溢出异常。 提示: 当session加载了customer对象后,会为customer对象的值类型的属性复制一份快照。当清理 缓存时,通过比较对象的当前属性和快照,来判断对象的那些属性发生了变化。北京传智播客教育 www.itcast.cn
  • 85. 操纵持久化对象理解session的缓存Session在清理缓存时,按照以下顺序执行sql语句。 1。按照应用程序调用save()方法的先后顺序,执行所有的对实体进行插入的insert语句。 2。所有对实体进行更新的update语句。 3。所有对实体进行删除的delete语句。 4。所有对集合元素进行删除、更新或插入的sql语句。 5。执行所有对集合进行插入的insert语句。 6。按照应用程序调用delete()方法的先后执行。 默认情况下: 1。当应用程序commit()方法的时候,先清理缓存,然后在向数据库提交事务。 2。当调用find()或iterator()时,如果对象属性发生变化,会先清理缓存,以保证查询结果 能够反映持久化对象的最新状态。 3。显式调用flush()。 --------------------------------------------------------------------------------------------- 提示: Commit()和flush()方法的区别: Flush进行清理缓存的操作,执行一些列sql语句,但不提交事务;commit方法先调用flush方 法,然后提交事务。提交事务意味着对数据库操作永久保存下来。北京传智播客教育 www.itcast.cn
  • 86. 操纵持久化对象理解session的缓存 session.setFlushMode(FlushMode.AUTO);清理缓存的模式Session的 查询方法tx的 commit()Session的 flush()FlushMode.AUTO清理清理清理FlushMode.COMMIT不清理清理清理FLushMode.NEVER不清理不清理清理北京传智播客教育 www.itcast.cn
  • 87. 操纵持久化对象在hibernate中java对象的状态临时状态(transient):刚刚用new语句创建,没有被持久化,不处于session中。该对象 成为临时对象 持久化状态(persistent):已经被持久化,加入到session的缓存中。该状态的对象为持久 化对象。 游离状态(detached):已经被持久化,但不处于session中。该状态的对象为游离对象。北京传智播客教育 www.itcast.cn
  • 88. 操纵持久化对象程序代码生命周期状态tx = session.beginTransaction(); Customer c = new Customer);开始生命周期临时状态Session.save(c)处于生命周期中转变为持久化状态Long id=c.getId(); c = null; Customer c2 = (Customer)session.load(Customer.class,id); tx.commit();处于生命周期中处于持久化状态session.close();处于生命周期中转变为游离态c2.getName();处于生命周期中处于游离态c2 = null;结束生命周期结束生命周期北京传智播客教育 www.itcast.cn
  • 89. 操纵持久化对象在hibernate中java对象的状态 临时对象特征 不处于session中,不被任何session关联。 数据库中没有对应的记录。 以下情况,对象进入临时状态: 1.new 语句刚创建了一个对象。 2.session的delete方法使持久化对象或游离 对象转变为临时对象,对于游离对象,该方法从数 据库中删除记录,对于持久化对象,该方法从数据 库中删除记录,还要删除缓存中的对象。北京传智播客教育 www.itcast.cn
  • 90. 操纵持久化对象在hibernate中java对象的状态 持久化对象特征 1.位于一个session缓存中,总是被一个 session关联。 2.持久化对象和数据库记录相对应。 3.清理缓存时,会根据对象属性变化,同步 更新数据库。 4.save把临时对象转变为持久化对象。 5.load或find或get返回的对象总是持久化状态。 6.find方法返回的list存放的都是持久化对象。 7.update、save、SaveOrUpdate和Lock方法使游离对象装变 为持久化对象。 在实际的应用程序中应该避免一个java对象被多个session实例关 联,会导致重复执行sql语句,并且极容易出现一些并发问题。北京传智播客教育 www.itcast.cn
  • 91. 操纵持久化对象在hibernate中java对象的状态 游离对象特征 1.不再位于session的缓存中,游离对象不被 session关联。 2.游离对象由持久化转变过来的,因此在数据 库中可能还存在与它对应的记录(前提条 件是没有其他程序删除了这条记录)。北京传智播客教育 www.itcast.cn
  • 92. 操纵持久化对象在hibernate中java对象的状态 游离对象特征 在以下情况下,持久化对象转变为游离对象: 1.close方法使缓存被清空,缓存中的所有的 对象都变为游离对象。如果没有引用他们 的话,他们就会结束生命周期。 2.evict方法从缓存中删除一个持久化对象, 使他变为游离态对象。当缓存中保存了大量的持久 化对象时,会消耗许多内存空间,使用该方法删掉 一些对象来节省空间。北京传智播客教育 www.itcast.cn
  • 93. 操纵持久化对象Session的增、删、改、查方法 save: 1.对象加入缓存,成为持久化对象。 2. 北京传智播客教育 www.itcast.cn
  • 94. 操纵持久化对象Session的增、删、改、查方法 update: 将游离对象转变为持久化对象。不论对象属性 是否发生变化,该方法都会执行update操作。如果希望仅当属性变化时才执行update语句的话可进行如下配置: 北京传智播客教育 www.itcast.cn
  • 95. 操纵持久化对象Session的增、删、改、查方法 saveOrUpdate: 该方法同时包含save和update方法,如果参数是临时对象就用save方法,如果是游离对象就用update方法,如果是持久化对象就直接返回。临时对象判断法: 1。OID为null 2。具有version属性并取值为null 3。在映射文件中为元素设置了unsaved-value属性,并且OID属性取值与属 性匹配。 4。在映射文件中为元素设置了unsaved-value属性,并且version属性取 值与属性匹配。 5。自定义了Interceptor实现类,并且isUnsaved方法返回Boolean.true 如果id的类型为long,则默认值为0,此时需要在配置文件中设置id的unsaved-value 为0。北京传智播客教育 www.itcast.cn
  • 96. 操纵持久化对象Session的增、删、改、查方法 load和get: 从数据库加载指定的OID持久化对象。 如果数据库中不存在该记录时,load方法会 抛出异常,而get方法返回null。北京传智播客教育 www.itcast.cn
  • 97. 操纵持久化对象Session的增、删、改、查方法 delete 如果参数是持久化对象,就执行一个delete语句,若为游离对象,先使游离对象被session关联,使他变为持久化对象,然后计划执行一个delete语句。北京传智播客教育 www.itcast.cn
  • 98. 操纵持久化对象Session的增、删、改、查方法cascade属性值描述none忽略关联对象,默认值save-update保存或更新当前对象时,级联保存关联的临时对象,更新关联的游离对象。delete删除对象时,级联删除关联的对象。all包含save-update和delete的行为。delete-orphan删除所有和当前对象解除关联关系的对象。all-delete-orphan包含all和delete-orphan的行为。北京传智播客教育 www.itcast.cn
  • 99. 操纵持久化对象与触发器协同工作Session.save(c); Session.flush(); Session.refresh(c); ------------------------------------------------------ 触发器的行为导致缓存与数据库中的数据不一致。解决办法是执行完 操作后,立即调用session的flush方法和refresh方法,迫使缓存与 数据库同步。 Session的update操作方法盲目的激活触发器 如果游离状态的对象的属性和数据库一致,则更新操作是多余的。 为避免这种情况: …… 北京传智播客教育 www.itcast.cn
  • 100. 映射组成关系北京传智播客教育 www.itcast.cn
  • 101. 映射组成关系Class customer{ …… Address homeAddress ; Address comAddress ; …… }Table customers{ …… home_province home_city home_street com_province com_city com_street …… } 北京传智播客教育 www.itcast.cn
  • 102. 映射组成关系映射组成关系 区分值和实体 持久化类的属性分为两种:值(value)类型和实体类型(entity)类型。值类型没有OID,不能被单独持久化,他的生命周期依赖于所属的持久化类的对象的生命周期,组件类型就是一种值类型;实体类型有OID,可单独持久化。北京传智播客教育 www.itcast.cn
  • 103. 映射组成关系映射组成关系 访问由组成关系的持久化类1.Conf.addClass(Customer.class).addClass(Address.class); 抛映射异常,原因是Address.hbm.xml文件没找到。 2. Customer c = new Customer(); c.setHomeAddress(new Address()); c.setComAddress(new Address()); …… Session.save(c); ---------------------------------------------------- Session.save(new Address()); 映射异常:unkown entity class.北京传智播客教育 www.itcast.cn
  • 104. 映射组成关系映射复合组成关系Computer类和他的组件类北京传智播客教育 www.itcast.cn
  • 105. 映射组成关系映射复合组成关系 北京传智播客教育 www.itcast.cn
  • 106. Hibernate映射类型内置映射类型Hibernatejavasql取值范围integer int int IntegerINTEGER4longlong LongBIGINT8shortshort ShortSMALLINT2bytebyte ByteTINYINT1floatfloat FloatFLOAT4doubledouble DoubleDOUBLE8big_decimaljava.math.BigDecinimalNUMERIC8位含2位小数部分characterchar Character StringCHAR(1)定长字符stringStringVARCHAR变长串booleanboolean BooleanBIT布尔yes_noboolean BooleanCHAR(1)布尔true_falseboolean BooleanCHAR(1)布尔北京传智播客教育 www.itcast.cn
  • 107. Hibernate映射类型java时间和日期类性Hibernatejavasql取值范围dateutil.Date sql.DateDATEYYYY-MM-DDtimeutil.Date sql.TimeTIMEHH:MM:SStimestamputil.Date sql.timestampTIMESTAMPYYYYMMDDHHMMSScalendarjava.util.CalendarTIMESTAMPYYYYMMDDHHMMSScalendar_datejava.util.CalendarDATEYYYY-MM-DD北京传智播客教育 www.itcast.cn
  • 108. Hibernate映射类型大对象类型的映射Hibernatejavasqlbinarybyte[]VARBINARY(BLOB)textStringCLOBserializable实现类BARBINARY(BLOB)clobsql.ClobCLOBblobsql.BlobBLOB不允许以上类型来定义OID北京传智播客教育 www.itcast.cn
  • 109. Hibernate映射类型大对象类型的映射如果持久化类的字段为blob或clob类型,保存时需要包含两步: ------------------------------------------------- Customer c = new Customer(); //现保存一个空的clob实例 c.setDescription(Hibernate.createClob()); session.save(c); session.flush(); //锁定记录 session.refresh(customer,LockMode.UPGRADE); oracle.sql.CLOB clob = c.getDescription(); //写入大文本 java.io.Writer pw = clob.getCharacterOutputStream(); pw.write(longtext); pw.close(); tx.commit(); session.close();北京传智播客教育 www.itcast.cn
  • 110. Hibernate映射类型JDK自带的个别java类的映射类型Hibernatejavasqlclassjava.lang.ClassVARCHARlocalejava.util.LocaleVARCHARtimezonejava.util.TimeZoneVARCHARcurrencyjava.util.CurrencyVARCHAR北京传智播客教育 www.itcast.cn
  • 111. Hibernate的检索策略hibernate的检索策略简介检索策略的作用域可选的检索策略默认的检索策略运行时行为受影响的session的检索方法类级别立即 延迟延迟load关联级别立即 延迟 迫切左外连接检索延迟load get延迟类级别和关联级别可选的检索策略及默认的检索策略北京传智播客教育 www.itcast.cn
  • 112. Hibernate的检索策略检索策略的类型类级别关联接别立即立即加载检索方法制定的对象立即加载关联的对象、可设定批量检索数量延迟检索延迟加载检索方法指定的对象延迟加载与检索方法指定的对象关联对象。可设定批量检索数量。迫切左外不适用通过左外连接加载与检索方法指定的对象关联的对象。三种检索策略的运行机制hibernate的检索策略简介(续)北京传智播客教育 www.itcast.cn
  • 113. Hibernate的检索策略属性可选值默认值描述lazytrue falsefalse如果为true,延迟加载,class和set有此属性fetchauto true false中为auto, 在元素中为false。如果为true,适用迫切左外连接检索。在 中存在。batch-size正整数1合理取值3~10之间,class和set存在。hibernate的检索策略简介(续)映射文件中用于设定检索策略的几个属性北京传智播客教育 www.itcast.cn
  • 114. Hibernate的检索策略类级别的检索策略 立即 延迟检索 if(!Hibernate.isInitialized(c)){ Hibernate.initialize(c); }北京传智播客教育 www.itcast.cn
  • 115. Hibernate的检索策略一对多和多对多关联的检索策略(set)北京传智播客教育 www.itcast.cn
  • 116. Hibernate的检索策略一对多和多对多关联的检索策略 立即检索 延迟检索 批量延迟检索 批量立即检索 迫切左外连接检索北京传智播客教育 www.itcast.cn
  • 117. Hibernate的检索策略多对一和一对一的检索策略北京传智播客教育 www.itcast.cn
  • 118. Hibernate的检索策略比较三种检索策略检索策略优点缺点优先考虑使用的场合立即检索对应用程序完全透明,不管对象处于持久化状态还是游离状态,应用程序都可以从一个对象导航到关联的对象(1)select语句多 (2)可能会加载应用程序不需要访问的对象,浪费许多内存空间。(1)类级别 (2)应用程序需要立即访问的对象 (3)使用了二级缓存延迟检索由应用程序决定需要加载哪些对象,可以避免执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并节省内存空间。应用程序如果希望访问游离状态的代理类实例,必须保证她在持久化状态时已经被初始化。(1)一对多或者多对多关联 (2)应用程序不需要立即访问或者根本不会访问的对象迫切左外连接检索(1)对应用程序完全透明,不管对象处于持久化状态还是游离状态,都可从一个对象导航到另一个对象。 (2)使用了外连接,select语句少(1)可能会加载应用程序不需要访问的对象,浪费内存。 (2)复杂的数据库表连接也会影响检索性能。(1)多对一或一对一关联 (2)需要立即访问的对象 (3)数据库有良好的表连接性能。北京传智播客教育 www.itcast.cn
  • 119. hibernate检索方式1。对象导航图 2。OID检索 3。HQL检索 4。QBC检索 5。本地SQL检索北京传智播客教育 www.itcast.cn
  • 120. hibernate检索方式检索方式简介 HQL检索方式1。在查询语句中设定各种查询条件 2。支持投影,仅检索出对象的部分属性 3。支持分页 4。连接查询 5。分组查询 6。内置聚集函数 7。调用用户自定义的函数 8。嵌入式查询 9。动态绑定参数Query query = session.createQuery(“from Customer as c where c.name=:custoerNa me and c.age = :customerAge”); query.setString(“customerName”,”Tom”); query.setInteger(“customerAge,21); query.list();北京传智播客教育 www.itcast.cn
  • 121. hibernate检索方式检索方式简介 QBC检索方式主要由Criteria、Criterion接口和Expression类组成,他支持在运行时动态生成查询语句。 ------------------------------------------------------------------------------------------ Criteria criteria = session.createCriteria(Customer.class); Criteria c1 = Expression.like(“name”,”T%”); Criteria c2 = Expression.eq(“age”,new Integer(21)); criteria.add(c1) criteria.add(c2); criteria.list(); ------------------------------------------------------------------------------------------ 方法链编程: session.createCriteria(Customer.class).add(Expression.like(“name”,”%T”)) .add(Expression.eq(“age”,new Integer(21))) .list(); 北京传智播客教育 www.itcast.cn
  • 122. hibernate检索方式检索方式简介 SQL检索方式Query query = session.createSQLQuery(“select {c.*} from CUSTOMERS c where c.NAME like :customerName and c.AGE=:customerAge”,”c”, Customer.class); //动态绑定参数 query.setString(“customerName”,”T%”); query.setInteger(“customerAge”,new Integer()21); //执行sql select语句,返回查询结果。 List list = query.list();北京传智播客教育 www.itcast.cn
  • 123. hibernate检索方式检索方式简介 使用别名from Customer as c where c.name = :customerName as 可省略。北京传智播客教育 www.itcast.cn
  • 124. hibernate检索方式检索方式简介 多态查询session.createQuery(“from Employee”); 查询出所有的实体 from java.lang.serializable(支持接口) from java.lang.Object北京传智播客教育 www.itcast.cn
  • 125. hibernate检索方式检索方式简介 对查询结果排序hql 查询: session.createQuery(“from Employee c order by c.name”); qbc查询: session.createCriteria(Customer.class).addOrder(Order.asc(“name”));分页查询hql 查询: session.createQuery(“from Employee c order by c.name”).setFirstResult(97) .setMaxResults(10); qbc查询: session.createCriteria(Customer.class) .aaddOrder(Order.asc(“name”)) .setFirstResult(97).setMaxResult(10).list();北京传智播客教育 www.itcast.cn
  • 126. hibernate检索方式检索方式简介 检索单个对象(要确保查询结果有且只有一条记录)hql 查询: session.createQuery(“from Employee c order by c.name”) .setMaxResults(1).uniqueResult(); qbc查询: session.createCriteria(Customer.class) .addOrder(Order.asc(“name”)) .setMaxResult(1).uniqueResult();北京传智播客教育 www.itcast.cn
  • 127. hibernate检索方式检索方式简介 绑定参数hql 查询: session.createQuery(“from Employee c where c.name = :customerName”); query.setString(“customeName”,”Tom”); ---------------------------------------------------- ............................c.name=? query.setString(0,”Tom”);北京传智播客教育 www.itcast.cn
  • 128. hibernate检索方式检索方式简介 在影射文件中定义命名查询语句 ....... ------------------------------------------------------------------ query = session.getNamedQuery(“findCustomersByName”); query.setString(“name”,”Tom”); query.list();北京传智播客教育 www.itcast.cn
  • 129. hibernate检索方式设定查询条件运算类型HQL运算符QBC运算方法含义比较运算=Express.eq()<>Express.not(Express.eq())>=Express.ge()
  • 130. hibernate检索方式设定查询条件(续)运算类型HQL运算符QBC运算方法含义字符串模式匹配likeExpression.like()逻辑andExpression.and()| Expression.conjunction()orExpression.or()| Expression.disjunction()notExpression.not()北京传智播客教育 www.itcast.cn
  • 131. hibernate检索方式连接查询 程序中指定的连接查询类型HQL语法QBC语法适用范围内连接inner join | joinCriteria.createAlias()适用于由关联关系的持久化类迫切内连接inner join fetch | join fetch不支持隐式内连接不支持左外连接left out join out join不支持迫切左外连接left out join fetch out join fetchFetchMode.EAGER右外连接right out join | out join不支持交叉连接ClassA,ClassB不支持适用于不存在关联关系的持久化类北京传智播客教育 www.itcast.cn
  • 132. hibernate检索方式连接查询 迫切左外连接HQL: createQuery(“from Customer c left join fetch c.orders o where c.name like ‘T%’”); QBC: createCriteria(Customer.class) .setFetchMode(“orders”,FetchMode.EAGER) .add(Expression.like(“name”,”T”,MatchMode.START))北京传智播客教育 www.itcast.cn
  • 133. hibernate检索方式连接查询 左外连接HQL: createQuery(“from Customer c left join c.orders o where c.name like ‘T%’”);北京传智播客教育 www.itcast.cn
  • 134. hibernate检索方式连接查询 内连接HQL: createQuery(“from Customer c inner join c.orders o where c.name like ‘T%’”); HQL: createQuery(“from Customer c join c.orders o where c.name like ‘T%’”); QBC: createCriteria(Customer.class). .add(Expression.like(“name”,”T”,MatchMode.START)) .createCriteria(“orders”) .add(Expression.like(“orderNumber”,”T”,MatchMode.START));北京传智播客教育 www.itcast.cn
  • 135. hibernate检索方式连接查询 迫切内连接HQL: createQuery(“from Customer c inner join fetch c.orders o where c.name like ‘T%’”); QBC: createCriteria(Customer.class). .setFetchMode(“orders”,FetchMode.EAGER) .createAlias(“orders”,”o”) .add(Expression.like(“this.name”,”T”,MatchMode.START)) .add(Expression.like(“o.orderNumber”,”T”,MatchMode.START))北京传智播客教育 www.itcast.cn
  • 136. hibernate检索方式连接查询 隐式内连接HQL: createQuery(“from Order o where o.customer.name like ‘T%’“); 等价于: from Order o join o.customer c where c.name like ‘T%’ QBC: 不支持北京传智播客教育 www.itcast.cn
  • 137. hibernate检索方式连接查询 右外连接HQL: from Customer c right outer join c.orders o where o.name like ‘T%’ 等价于: from Customer c right join c.orders o where o.name like ‘T%’北京传智播客教育 www.itcast.cn
  • 138. hibernate检索方式连接查询 使用SQL风格的交叉连接和隐式内连接HQL: 交叉连接查询:from Customer,Order 标准SQL风格的内连接:from Customer c inner join c.orders SQL风格的隐式内连接查询:from Customer c,Order o where c.id = o.customer_id北京传智播客教育 www.itcast.cn
  • 139. hibernate检索方式连接查询 关联级别运行时的检索策略 1.若在HQL、QBC代码中没有显式指定检索策 略,使用映射文件中的检索策略。但HQL总是忽略 映射文件中设置的迫切左外连接检索策略。 2.若代码中显示指定了检索策略,则覆盖映射文件中 的检索策略。 3.目前的hibernate版本只允许在一个查询语句中迫切 左外连接检索一个集合。 4.HQL支持各种各样的连接查询。北京传智播客教育 www.itcast.cn
  • 140. hibernate检索方式报表查询 投影查询 指查询结果仅包括部分实体或实体的部分属 性。通过select来实现。from Customer c join c.orders o where o.orderNumber like ‘T%’ 如果希望查询结果中只包含Customer对象,可使用以下形式: select c from Customer c join c.orders o where o.orderNumber like T%’ session.createQuery(“select c.id,c.name,o.orderNumber from Customer c join c.orders o where o.orderNumber like ‘T%’”) ----------------------------------------------------------------------------------- 对应的sql语句为: select c.ID,c.NAME,o.ORDER_NUMBER from CUSTOMERS c inner join ORDERS o on c.ID-=o.CUSTOMER_ID where o.ORDER_NUMBER like’T%’ ------------------------------------------------------------------------------------ 过滤重复元素 createQuery(“select distinct c.name from customer c”);北京传智播客教育 www.itcast.cn
  • 141. hibernate检索方式报表查询 使用聚集函数 createQuery(“select count(*) from Customer c”).uniqueResult(); createQuery(“select avg(c.age) from Customer c”).uniqueResult(); createQuery(“select max(c.age),min(c.age) from Customer c”).uniqueResult(); 分组查询: createQuery(“select c.name,count(c) from Customer group by c.name”);北京传智播客教育 www.itcast.cn
  • 142. hibernate检索方式高级查询技巧动态查询: session.createCriteria(Customer.class) .add(Expression.like(“name”,name.toLowerCase()),MatchMode.ANYWHERE) .add(Expression.eq(“age”,new Integer(11))); 集合过滤: hql: createQuery(“from Order o where o.customer=:customer and o.price>100 order by o.price”).setEntity(“customer”,customer).list(); 使用集合过滤: session.createFilter(customer.getOrders(),”where this.price > 100 order by this.price”).list(); 子查询: from Customer c where 1 < (select count(o) from c.orders o); 本地SQL查询: String sql=“select cs.ID as {c.id},cs.NAME as {c.name},cs.AGE as {c.age} from CUSTOMERS cs where cs.ID = 1”; Query query = session.createSQLQuery(sql,”c”,Customer.class); 第二个参数是类的别名,在SQL语句中,每个字段的别名必须位于打括号内。北京传智播客教育 www.itcast.cn
  • 143. hibernate检索方式查询性能优化 iterate方法query1=session.createQuery(“from Customer c”); List result1 = query1.list(); Query query2 = session.createQuery(“from Customer c where c.age < 30”); Iterator it = query2.iterator(); query接口的iterate方法首先检索ID字段,然后根据ID字段到一级缓存、二级缓存中查 找,有则返回,否则查库。北京传智播客教育 www.itcast.cn
  • 144. hibernate检索方式查询性能优化 查询缓存在hibernate.properties中的 hibernate.cache.use_query_cache=true query = session.createQuery(“from Cusotmer c where c.age>:age”); query.setInteger(“age”,new Integer(1)); query.setCacheable(true); ------ 如果想更加细粒度的控制查询缓存,可设置缓存区域 query.setCacheRegion(“customer”)北京传智播客教育 www.itcast.cn
  • 145. hibernate检索方式小结比较方面HQL检索QBC检索可读性优点:和sql相近,易读将语句肢解成一组criteria,较差功能支持各种查询不支持报表查询和子查询。有限的连接查询查询语句形式基于字符串形式的sql更加面向对象何时被解析运行时被解析编译时被解析,更易排错可扩展性不具扩展性用户可扩展criteria接口对动态查询语句的支持支持动态查询,编程麻烦适合动态生成查询语句北京传智播客教育 www.itcast.cn
  • 146. 影射继承关系整个关系树对应一个表(存在一个表中)北京传智播客教育 www.itcast.cn
  • 147. 影射继承关系每个类对应一个表(三个表,主从关系)北京传智播客教育 www.itcast.cn
  • 148. 影射继承关系关系树的每个具体类对应一个表北京传智播客教育 www.itcast.cn
  • 149. Hibernate数据库级别的并发理解数据库级别的并发 事务隔离问题-丢失更新:北京传智播客教育 www.itcast.cn
  • 150. Hibernate数据库级别的并发理解数据库级别的并发 事务隔离问题-脏读:北京传智播客教育 www.itcast.cn
  • 151. Hibernate数据库级别的并发理解数据库级别的并发 事务隔离问题-不可重复读:第二类丢失更新时不可重复读的一种特例.两个事务都更新同一数据,第一个 事务完成后提交,第二个事务完成时也提交.则第一个事务所做的修改被覆盖 了.此种现象为第二类丢失更新.北京传智播客教育 www.itcast.cn
  • 152. Hibernate数据库级别的并发理解数据库级别的并发 事务隔离问题-幻读:北京传智播客教育 www.itcast.cn
  • 153. Hibernate数据库级别的并发理解数据库级别的并发 ANSI 事务隔离级别 ANSI SQL 标准定义了隔离级别,但并不是SQL数据库独有.JTA也定义了同样的隔离级别.级别 越高,成本越高. 1.如果系统允许脏读但不会丢失更新我们称之为read uncommited隔离级别.一个事务不可能向 另外一个事务所控制的行在未提交的情况下写入数据.任何事务都可以读取任何行数据.这一隔离级 别可以通过的DBMS的排他写锁实现. 2.如果系统允许不可重复读但不能脏读我们称之为read commited隔离级别.这可以通过共享读锁和 排他写锁实现.读操作不会阻止其他事务访问行数据.然而一个未提交的写事务会阻止所有访问该行 的事务. 3.既不允许不可重复读也不允许脏读,我们称之为repeatable read.幻读还能够发生.读事务阻止 了写事务(不是其他的读事务).写事务阻止所有的其他事务. 4.Serializable提供了最严格的事务隔离级别.他按照串行化的方式执行事务,不支持并发访问,不能 只通过行级锁实现,必须用其他的一些机制来阻止其他新插入的行.北京传智播客教育 www.itcast.cn
  • 154. Hibernate数据库级别的并发理解数据库级别的并发 选择隔离级别 隔离级别过高损害高并发应用的可扩展性.级别不够也会引起莫名的问题.对于数据库的事务语义 来,Hibernate尽可能的做到透明.然而缓存和乐观锁会影响到这些语义.如何选择合理的隔离级别? 选择标准 1.消除读未提交隔离级别,使用未提交数据非常危险. 2.大多数应用不需要可串行化级别 3.在读已提交和可重复读间选择. 设置事务隔离级别允许为所有的数据库事务选择合理的锁策略.但如何设置? 设置隔离级别 每个数据库连接都有默认的隔离级别,通常是读已提交或可重复读.可以通过数据库配置设置,也可在 应用程序中设置.例如Hibernate: hibernate.connection.isolation = 4 1—Read uncommitted isolation 2—Read committed isolation 4—Repeatable read isolation 8—Serializable isolation 注意:Hibernate不可能改变在受管环境下由应用服务器提供的数据库连接的隔离级别,只能通过改变 应用服务器配置的方式来改变.设置隔离级别是全局选项,会影响所有的连接和事务.有时需要为 某个特定事务指定更多的限制.Hibernate依赖于乐观的并发控制,使用版本检查和 悲观锁实现附加的锁支持.北京传智播客教育 www.itcast.cn
  • 155. Hibernate乐观并发控制乐观并发控制 乐观并发控制只在工作单元结束后产生错误.多用户应用通常会默认采用乐观并发控制以及 与数据库连接采用读已提交的隔离级别.在特定的相应时刻可获得附加的这一隔离级别.比 如要求进行一个可重复的读,这一方案能够确保最佳的性能和扩展性. 理解乐观策略 有三种方案来处理在第二个事务中的丢失更新问题. 1.Last commit wins(后提交成功) 事务都成功,后提交覆盖前一个的改变,没有错误消息. 2.First commit wins(前提交成功) B提交时得到错误消息,要求必须重启会话,刷新数据后对非脏数据再进行操作. 3.Merge conflicting updates(合并冲突更新) A成功提交,B提交时伴随错误消息而终止,B用户可以选择性的应用变更,而不是重复会话中的 所有步骤.如果没有启动乐观并发控制,则运行在1模式下(默认值),结 果是导致没有任何错 误消息而丢失更新. 北京传智播客教育 www.itcast.cn
  • 156. Hibernate乐观并发控制理解乐观策略 如果没有启动乐观并发控制(默认不启动),程序运行于后提交成功模式(谁后提交谁有效,不关心数 据),用户可能对这种模式比较沮丧,自己所做的大量工作连个错误消息都没有的情况下丢失了! 很明显,后提交失败模式更吸引人.B提交时会得到错误消息,有其他人先修改数据了.提示用户刷新数 据后,重新启动会话. 第三种模式不显示错误消息而是强制用户后退所有的步骤.我们要提供对话框允许用户手动合并有冲 突的变更.这是一种最佳的方式,因为没有工作丢失,而且由于并发控制的失败用户也很少感觉到沮丧. 然而对于开发者来说提供对话框来合并变要比给出错误消息和重复用户所有工作会更耗时.这要留给 你来决定采用哪个策略.北京传智播客教育 www.itcast.cn
  • 157. Hibernate乐观并发控制乐观并发控制 在Hibernate中启动版本控制 版本与时间戳.该属性不应该由应用程序访问,因此访问级别应设置为field.对于时间戳来说,检索 JVM时间也不够安全,比如在集群环境下,某些节点没进行时间同步.我们需要从数据库所在主机检索 当前时间,这需要通过设置来实现,不是每个方言都支持(查看方言源 码).北京传智播客教育 www.itcast.cn
  • 158. Hibernate乐观并发控制乐观并发控制 版本机制的自动管理 没有版本号或时间戳的版本控制 若没有版本或时间戳字段,Hibernate也能实现版本控制,但仅限同一会话内.若游离对象要实现乐观 锁必须用版本或时间戳.这种版本的实现是通过对数据库的当前状态和最开始查询出来的数据对象进 行对比完成的.设置如下: Hibernate会执行如下sql语句: update ITEM set ITEM_PRICE='12.99‘ where ITEM_ID=123 and ITEM_PRICE='9.99‘ and ITEM_DESCRIPTION="An Item“ and ... and SELLER_ID=45 如果有并发产生的话,会更新0行.结果抛出脏对象异常. 另外,如果设置optimistic-lock=“dirty“,Hibernate只包含修改的属性.同时,还需要设置 dynamic-update=“true”. 这种方案不推荐使用.北京传智播客教育 www.itcast.cn
  • 159. Hibernate额外的隔离保证获得额外的隔离保证 有几种方式可以避免不可重复并升级到更高的隔离级别. 显式悲观锁 对于某个特定的工作单元需要更好的隔离保证.而不是应该采用一刀切的做法. 比如说,我们在标量查询中会需要可重复读: Item i = (Item) session.get(Item.class, 123); String description = session.createQuery("select i.description from Item i" +" where i.id = :itemid").setParameter("itemid", i.getId() ).uniqueResult(); 第二次查询可能返回一个和第一次查询不一致的描述数据,原因是在这两次查询期间有另外一个事务 改写了该item对象在数据库中的对应的description字段的值,而且提交了事务.结果造成了不可 重复读. 也就是如果数据库隔离级别为读已提交的话,则第二次的标量查询可能会读到其他事务提交的数据. 这是典型的不可重复读.(简单但很典型) 北京传智播客教育 www.itcast.cn
  • 160. Hibernate额外的隔离保证获得额外的隔离保 相对与把数据库连接切换到更高的可重复读的隔离级别来说,在hibernate中我们可以选择lock方法 来获得更强的隔离保证. Item i=(Item)s.get(Item.class,123); s.lock(i,LockMode.UPGRADE); String d=(String)s.createQuery("select.. 使用了LockMode.UPGRADE之后,可以保证在连续两次查询过程中,没有其他的并发事务可对其进行 修改.上面代码等同于以下代码: session.get(Item.class,123,LockMode.UPGRADE); LockMode.UPDATE会导致执行类似SELECT ... FOR UPDATE的SQL语句(依赖于数据库方言).还 有一种变形(LockMode.UPDATE_NOWAIT)北京传智播客教育 www.itcast.cn
  • 161. Hibernate额外的隔离保证获得额外的隔离保证 Hibernate Lock模式 1.LockMode.NONE: 不要访问数据库,对象在任何缓存中都不存在除外. 2.LockMode.READ: 越过所有缓存,执行一个版本检查验证内存中对象的版本和库中版本是否一致. 3.LockMode.UPGRADE: 越过所有缓存,进行版本检查并获得数据库级别的悲观UPGRADE锁.等价于JPA中的 LockModeType.READ.如果数据库方言不支持..for Update操作,则自动降格到 LockMode.READ. 4.LockMode.UPGRADE_NOWAIT: 等价于3,会执行..for update nowait操作,如果不能立即获得事务的话,不会等待,而是直接抛 出异常. 5.LockMode.FORCE: 强行增加对象在记录中的版本号,表明已经被当前事务修改.等价于JPA中LockModeType.WRITE 6.LockMode.WRITE: Hibernate写操作时自动获得,应用程序不需要指定.北京传智播客教育 www.itcast.cn
  • 162. Hibernate传播session传播hibernate session 有些操作跨越多个dao,但还要保证事务管理.如何实现? 通过Thread-local传播 在dao中需要访问当前会话,且没有事务边界北京传智播客教育 www.itcast.cn
  • 163. Hibernate传播session通过Thread-local传播(线程本地化) 在dao中需要访问当前会话,且不需要定义事务边界. public class ItemDAO { public Bid getMaxBid(Long itemId) { Session s = getSessionFactory().getCurrentSession(); return (Bid) s.createQuery("...").uniqueResult(); } ... } 在控制器中(Action)或service中,定义是事务的边界. sf.getCurrentSession().beginTransaction(); dao1.xxx(..); dao2.xxx(..); Dao3.xxx(..); .. sf.getCurrentSession().getTransaction().commit(); 注:需要设置hibernate.current_session_context_class=thread北京传智播客教育 www.itcast.cn
  • 164. Hibernate传播session使用JTA传播 在dao中仍然使用sf.getCurrentSession(). 在控制器或service中代码如下: utx=(UserTransaction)newInitialContext().lookup("UserTransaction") utx.begin(); dao1.xxx(); dao2.xxx(); utx.commit(); 若用jta方式部署程序的话,则不必启动jta事务边界处理,因为getCurrentSession()方法总是返 回一个范围化的session并且绑定到当前的jta系统事务上. 注意:Hibernate事务接口和getCurrentSession()以及JTA不能一同使用北京传智播客教育 www.itcast.cn
  • 165. Hibernate批量操作直接在db中更新 Query q = s.createQuery("update Item i set i.isActive = :isActive"); q.setBoolean("isActive", true); int res = q.executeUpdate(); 直接创建新对象 "insert into StolenCreditCard(type, number, expMonth) select c.type, c.number, where …北京传智播客教育 www.itcast.cn
  • 166. Hibernate批量操作批量处理(更新) ScrollableResults itemCursor = session.createQuery("from Item").scroll(); int count=0; while ( itemCursor.next() ) { Item item = (Item) itemCursor.get(0); modifyItem(item); if ( ++count % 100 == 0 ) { session.flush(); session.clear(); } } tx.commit(); session.close();北京传智播客教育 www.itcast.cn
  • 167. Hibernate批量操作批量插入 for ( int i=0; i<100000; i++ ) { Item item = new Item(...); session.save(item); if ( i % 100 == 0 ) { session.flush(); session.clear(); }北京传智播客教育 www.itcast.cn
  • 168. Hibernate批量操作使用无状态session Session session = sessionFactory.openStatelessSession(); Transaction tx = session.beginTransaction(); ScrollableResults itemCursor = session.createQuery("from Item").scroll(); while ( itemCursor.next() ) { Item item = (Item) itemCursor.get(0); modifyItem(item); session.update(item); } tx.commit(); session.close();北京传智播客教育 www.itcast.cn
  • 169. Hibernate批量操作使用subselect关联检索策略 select i.* from ITEM i select b.* from BID b where b.ITEM_ID in (select i.ITEM_ID from ITEM i) 查询多个Item对象.北京传智播客教育 www.itcast.cn
  • 170. Hibernate缓存基础缓存基础 缓存用于性能优化,非JPA和EJB规范,不同厂商方案不同 缓存维护数据状态在本地,内存或者磁盘 缓存会减少数据库访问 缓存策略与范围 缓存类型 一.事务范围:位于当前工作单元,不能并发访问 二.进程范围:多个工作单元共享,可并发访问,可存储实例本身也可存散列数据,然后在 重新组装 三.集群范围:多个进程和主机间访问,网络通信是重点.需要将数据复制到所有集群中的节点. 缓存和OID: 事务级缓存也用于对象id的使用范围,是理想的缓存 进程级缓存可选择实现id的进程范围存储,也和主键对应.并发工作单元查询同一id对象的话返 回相同的实例.在进程级缓存中的对象也可按值返回,每个工作单元再重新组装形成副本.北京传智播客教育 www.itcast.cn
  • 171. Hibernate缓存策略与范围缓存策略与范围 集群级缓存:始终需要远程通信. 缓存与并发 一级缓存是强制的,他也维护了OID,二级缓存(进程级/集群级)对某些数据来说是有用的. 缓存与事务隔离 应用存在非独占性的数据访问,不该使用进程级缓存(金融系统) 非独占访问典型情况 一、集群应用 二、共享遗留数据 适合二级缓存的类的特征: 一、很少改变 二、不共享的本地数据 三、不重要的数据北京传智播客教育 www.itcast.cn
  • 172. Hibernate缓存策略与范围缓存策略与范围 适合二级缓存的类的特征(参考数据-数据字典): 四、对象数量很少 五、被很多类引用 六、很少被更新 Hibernate缓存架构 1、一级缓存即session. 2、二级缓存是可配的插件,可用于进程/集群范围缓存.他们缓存都是状态(按值返回), 而不是真正的持久化对象.对于特定的数据项来说缓存的并发策略定义了事务的 隔离细节.每个类或者每个集合的二级缓存是可选可配的.每个缓存都使用了自己 的缓存区域. 3、Hibernate还实现了对查询结果集的缓存,他和二级缓存紧密结合.而且需要额外 的两个物理缓存区域来容纳缓存的查询结果和最后更新表的时间戳.北京传智播客教育 www.itcast.cn
  • 173. Hibernate缓存架构二级缓存架构北京传智播客教育 www.itcast.cn
  • 174. Hibernate缓存架构 Hibernate二级缓存 1、所有通过同一sf开启的会话共享同一二级缓存 2、对象以拆解的形式存于二级缓存中(拆解是串行化过程,算法更多,更快比java串行) 3、重点在于缓存方案(缓存策略与物理缓存提供商) 4、不同数据需要不同的缓存方案.涉及如下设置: a、是否开启二级缓存 b、Hibernate并发策略 c、缓存过期策略(timerout LRU 内存敏感) d、缓存的物理格式(内存 索引文件 集群替换) 二级缓存安装需要两步: 1、决定使用哪个缓存并发策略 2、配置缓存过期和物理缓存属性(cache provider)北京传智播客教育 www.itcast.cn
  • 175. Hibernate缓存架构Hibernate缓存架构 内置并发策略 并发策略是调解人,负责在缓存中检索数据.对于特定数据项,他也定义了事务隔离的语义.对类 或集合来说使用哪个并发策略需要做出判断. 四个内置的并发策略体现了递减的事务隔离的等级. 1、Transationsal 只在受管环境中使用,如果需要可以确保所有的事务隔离到可重复读,很少更新且防止脏数 据情况下该策略很重要 2、Read-write 该策略维护读已提交隔离级别,使用了时间戳机制只在非集群环境下使用. 3、Nostrict-read-write 不保证在数据库和缓存之间数据的一致性,如果使用的话,应该配置一个高效短期的过期超 时.否则,可能读到脏数据. 4、Read-only 适用于从不发生改变的数据.只对数据进行引用.约束的降低带来了性能提升. 还可以实现自定义策略: org.hibernate.cache.CacheConcurrencyStrategy北京传智播客教育 www.itcast.cn
  • 176. Hibernate缓存架构Hibernate缓存架构 选择缓存供应商 Hibernate要求必须为整个应用选择一个供应商.以下是开源的实现: 1、EHCache 适用于单个虚拟机中单个进程范围,可缓存至内存和磁盘,支持查询缓存(最新版本支持集群 缓存,未测试) 2、OpenSymphony OSCache 在单个虚拟机中缓存至内存或磁盘.支持丰富的过期策略和查询缓存. 3、SwarmCache 基于JGROUPS的集群缓存, 不支持Hibernate查询缓存 4、JBoss Cache 同样基于JGROUPS广播库的完全事务性自我复制集群缓存,支持自我复制、校验、同/异步 通信、乐观/ 悲观锁 不是每个缓存供应商对任何并发策略都支持.结果如下:北京传智播客教育 www.itcast.cn
  • 177. Hibernate缓存实践缓存实践 选择并发缓存策略 类数量有限、很少更改、被多个用户共享,是使用二级缓存的典型 如果需要导航到该类对象或load时,hibernate都会查询二级缓存.使用read-write而不是nostrict-read-write,是因为他是高并发类并在多个并发事务中共享,读已提交隔离级别足够.而nostrict-read-write要依赖于过期设置,我们首选应该是数据变更后立即可见.该缓存对于所有该类的子类都有效,我们不能只缓存某个特定的子类. 此设置缓存所有的该类简单的属性值,但不包括关联实体的状态和集合.集合要求有自己的缓存区域.
  • 178. Hibernate缓存实践缓存实践 选择并发缓存策略 集合缓存的区域名称是类名加属性名: auction.model.Category.items 该集合缓存只缓存了id,而并没有实例,如果需要Item实例自身也要缓存的话,必须开启Item 类的缓存. 北京传智播客教育 www.itcast.cn
  • 179. Hibernate缓存区域理解缓存区域 Hibernate在不同区域维护不同的类和集合.区域即命了名的缓存.通过它可引用类和集合还可以设置 区域的缓存的过期策略.区域有两种类型,一种存放拆解的实体数据,另一种只存放id并通过集合连接 在一起. 类缓存区域名是类名. 集合是类名加属性名. 还可以通过设置hibernate.cache.region_prefix属性为特定的sf指定区域前缀.则区域名 变为前缀名+”.”+区域名. 此设置对于应用中涉及多个sf有用,否则可能会冲突.接下来配置缓存的物理属性,先选缓存供应 商.北京传智播客教育 www.itcast.cn
  • 180. Hibernate设置缓存供应商设置本地缓存供应商 按以下配置设置: hibernate.cache.provider_class=org.hibernate.cahe.EhCacheProvider EHCache有自己的配置文件,位于类路径跟下,名称为 ehcache.xml: 181. Hibernate-EHCache缓存配置设置本地缓存供应商(续) 因为该类实例有限,通过设置缓存大小限制大于类实例数来关闭溢出设置,同时设置永不过期 (eternal=true),由于该类缓存并发策略是read-write,所以用超时(timeout)使缓存数据过期是没必 要的.而且也没有其他应用直接在库中修改数据.我们也关闭了基于磁盘的缓存溢出,因为该类的实例有 限内存消耗不是问题. 另外,Bid很小 不可变但数量很多,所以必须要配置内存消耗.我们同时设置过期超时和最大缓存大 小限制: 北京传智播客教育 www.itcast.cn
  • 182. Hibernate-EHCache缓存配置设置本地缓存供应商(续) timeToIdleSeconds:空闲时间(发呆时间) timeToLiveSeconds:存活时间(放入缓存开始计时) maxElementsInMemory:内存中最大元素量(元素量超过该值时,最近最少使用的元素被删除) overflowToDisk:溢出至磁盘(由于与db位于同一机器,关闭该设置,否则,本地访问要快于网络访问) 北京传智播客教育 www.itcast.cn
  • 183. Hibernate控制二级缓存控制二级缓存 hibernate.cache.use_second_level_cache=false 该属性可全局控制二级缓存开关.默认情况,映射文件(或其他)的cache元素都会触发二级缓存的加载, 使用该属性可避免删除元素控制二级缓存. sf控制二级缓存: sf.evict(xx.class,id);//删除指定类缓存区域中指定id对象. sf.evict(‘org…Category”);//删除指定类缓存区域的所有缓存的对象. 该操作是非事务性的,没有锁机制. Hibernate提供了CacheMode,可为特定的session激活,他控制和二级缓存交互. s.setCacheMode(CacheMode.IGNORE); s.save(c); 则该对象同时被加入到二级缓存中.北京传智播客教育 www.itcast.cn
  • 184. Hibernate控制二级缓存控制二级缓存 s = sf.openSession(); tx = s.beginTransaction(); s.get(Customer.class,1); new Thread(){ public void run(){ s.. s.get(Customer.class,1); .. } }.start(); s.get(c1);//是否查库?why tx.commit(); s.close(); s = sf.openSession(); tx = s.beginTransaction(); s.get(Customer.class,1); tx.commit(); s.close();北京传智播客教育 www.itcast.cn
  • 185. Hibernate控制二级缓存控制二级缓存 1.CacheMode.NORMAL 默认值 2.CacheMode.IGNORE 从不和二级缓存交互,除了更新时废除数据 3.CacheMode.GET 可以查询,但不添加除了更新时废除数据 4.CacheMode.PUT 从不查询,但查库时添加数据 5.CacheMode.REFRESH 同put,该模式下,hibernate.cache.use_minimal_puts属性被屏蔽.在自我复制缓存 集群缓存下为了强制缓存刷新可使用该模式.北京传智播客教育 www.itcast.cn
  • 186. Hibernate缓存查询结果缓存查询结果 二级缓存是数据共享缓存,当访问未加载的代理类实例或者集合或者按照oid检索的时 候,hiberante都会到一、二级缓存中进行查找.默认情况下,查询结果是不缓存的.如果通过iterator() 方法进行查询,只从数据库中查询主键值.而实体数据会从一、二级缓存中查找. 而缓存查询结果是完全不同的问题.他默认是关闭的,每个HQL,JPA QL,SQL和Criteria总是首先要 访问数据库. 启动查询结果缓存 hibernate.cache.use_query_cache = true q.setCacheable(true); 缓存区域名称不同于类/集合缓存,默认情况下域名为 org.hibernate.cache.QueryCache 该方法在QBC中也可用,JPA使用setHint("org.hibernate.cacheable", true) 也可显式设置区域名称:q.setCacheRegion(“my.cache”); 不过很少使用,除非有特殊的缓存方案.北京传智播客教育 www.itcast.cn
  • 187. Hibernate缓存查询结果理解查询缓存 当某个查询被首次执行时,该结果被缓存到缓存区域.该区域不同于实体和集合的缓存区域.他的缓存 区域的默认的名字是org.hibernate.cache.QueryCache.也可以显式设置区域名称. categoryByName.setCacheRegion("my.Region") 标准的查询结果缓存区域容纳的是sql语句(携带绑定参数)以及结果集.这并不是全部的SQL结 果集.如果结果集包含实体对象,结果集缓存只存放id值.其他数据在放入缓存时就被销毁了.而二级 缓存的实体缓存区负责缓存实体的状态.这和iterator方法有些相似.所以如果要对某个查询结果进 行缓存的话,一定要将对应的实体缓存(二级缓存)打开,不然会有更多的数据库访问. 如果缓存的查询结果不是实体,而是一些标量值,这些值直接存放在查询结果缓存中. 如果查询结果缓存开启的话,另一个缓存区域也会要求开启-org.hibernate.cache. UpdateTimestampsCache.该缓存是hibernate内置的缓存区域.hibernate是用时间戳区域来决 定缓存的查询结果是否过期(脏了).当重新执行查询时,hibernate会在时间戳缓存中查找最近对查 询表所做的插入、更新和删除的时间戳.若发现时间戳晚于要缓存的查询结果的时间戳,则缓存的结果 就要被丢弃并执行新的查询.这可以确保查询中的任何一个表如果包含了更新的数据的话,hibernate 都不会使用缓存的查询结果. 对于使用查询缓存时,必须所使用Query对象都进行相同的设置: q.setCachable(true);//该方法不仅意味着查询结果可缓存,还表示可到缓存中查询结果!!!. q.setCacheRegion(..);//如果两次的缓存区域设置的不同,同样不能实现查询缓存的效果.北京传智播客教育 www.itcast.cn