hibernate持久化数据库第二天.ppt_第1页
hibernate持久化数据库第二天.ppt_第2页
hibernate持久化数据库第二天.ppt_第3页
hibernate持久化数据库第二天.ppt_第4页
hibernate持久化数据库第二天.ppt_第5页
已阅读5页,还剩130页未读 继续免费阅读

下载本文档

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

文档简介

hibernate 持久化数据库,第二天,概要,知识点一:java对象持久化(复习) 知识点二:Hibernate关联映射 (熟练掌握如下实体对象关联) 1、单向的ont-to-many 2、单向的many-to-one 3、双向的one-to-many 4、many-to-many 熟练掌握如下属性 1、cascade 级联操作 2、inverse 反转 3、lazy 延迟加载、懒加载,知识点一:Java对象持久化概述,Java对象持久化概述,Hibernate是什么 面向java环境的对象/关系数据库映射工具。 1.开源的持久层框架. 2.ORM(Object/Relational Mapping)映射工具,建立面向对象的域模型和关系数据模型之间的映射. 3.连接java应用和数据库的中间件. 4.对JDBC进行封装,负责java对象的持久化. 5.在分层结构中处于持久化层,封装对数据库的访问细节, 使业务逻辑层更专注于实现业务逻辑,Java对象持久化概述,为什么要用Hibernate 1、Hibernate对JDBC访问数据库的代码做了封装,大大简化 了数据访问层繁琐的重复性代码。 2、Hibernate是一个基于jdbc的主流持久化框架,是一个优秀 的orm实现,它很大程度的简化了dao层编码工作。 3、Hibernate使用java的反射机制,而不是字节码增强程序类实现 透明性 4、Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵 活性很出色。它支持很多关系型数据库,从一对一到多对多的各 种复杂关系。,Java对象持久化概述,Java 应用的持久化分层 为了把数据访问细节和业务逻辑分开, 可以把数据访问作为单独的持久化层,表述层,业务逻辑层,数据库层,表述层,业务逻辑层,持久化层,数据库层,Java对象持久化概述,Hibernate中间件:Hibernate不和特定的业务领域相关,能够把任意一个Java应用与数据库系统连接,可以理解为是一种中间件。,应用1,业务逻辑层,应用2,业务逻辑层,应用3,业务逻辑层,持久化层 (hibernate),数据库1,数据库2,数据库3,持久化层封装了数据访问的细节,为业务逻辑层提供了面向对象的API。完善的持久化层应该 达到的目标: 1.代码重用性高,可完成所有的数据访问操作。 2.如果需要的话,能够支持多种数据库平台。 3.具有相对独立性,当持久化层变化时,不会影响上层实现。,Java对象持久化概述,软件模型 概念模型:模拟问题域中的真实实体。描述每个实体的概念和属性及实体间关系。不描述实体行为。实体间的关系有一对一、一对多和多对多。,客户 Name age,订单 orderNumber price,1,*,Java对象持久化概述,软件模型 关系数据模型:在概念模型的基础上建立起来的,用于描述这些关系数据的静态结构。有以下内容组成: 1.若干表 2.表的所有索引 3.视图 4.触发器 5.表与表之间的参照完整性,Customers表 ID NAME AGE,ORDERS表 ID CustomerID Order_number price,Java对象持久化概述,软件模型 域模型:在软件的分析阶段创建概念模型,在软件设计阶段创建域模型。 组成部分: 1.具有状态和行为的域对象。 2.域对象之间的关联。,Java对象持久化概述,软件模型 域对象(domain object):构成域模型的基本元素就是域对象。对真实世界的实体的软件抽象,也叫做业务对象(Business Object(BO).域对象可代表业务领域中的人、地点、事物或概念。 域对象分为以下几种: 实体域对象:通常是指业务领域中的名词。(pojo) (plain old java object)。-映射数据库中的表 过程域对象:应用中的业务逻辑或流程。依赖 于实体域对象,业务领域中的动词。如 发出订单、登陆等。(对pojo操作的方法) 事件域对象:应用中的一些事件(警告、异常)。,面试题:,根据类之间的关系,分离下面语句中的对象,并说明对象之间的关系: 我早上出门先到公交车站乘坐公交车到地铁站,然后乘坐地铁到公司上班 有一间屋子,屋子有门,窗户,屋子中有一张床,一张椅子,椅子有四条腿,Java对象持久化概述,软件模型 域对象间的关系 1.关联:类间的引用关系。以属性定义的方式表现。,关联可分为一对一、一对多和多对多。还可分为单向关联和双向关联。,Order,Customer,Java对象持久化概述,软件模型 域对象间的关系 依赖:类之间访问关系。无需定义成属性。在A中访问B中的 方法或属性,或者A负责实例化B。,BusinessService,Customer,Java对象持久化概述,软件模型 域对象间的关系 3.聚集(Aggregation):整体与部分的关系。例人与手的关系。部分类的对象不能单独存在,他的生命周期依赖于整体类的对象的生命周期,整体消失时,部分也随之消失。,Person hand:set,Hand ,Java对象持久化概述,软件模型 域对象间的关系 4.一般化(Generalization):类之间继承关系。,Employee name,HourEmployee rate,SalaryEmployee salary,Java对象持久化概述,内存,Customer对象,order对象,数据库,持久化,重新加载到内存,软件模型 域对象的持久化概念 实体域对象在内存中创建后,不能永久存在。将实体域对象永久保存起来,就是持久化的过程。通常只有实体域对象需要持久化,过程域对象和事件域对象一般不需要持久化。广义持久化指增、删、改、查。,Java对象持久化概述,ORM:(Object/Relation Mapping): 对象/关系映射 主要解决对象-关系的映射 ORM的实现思想:将关系数据库中表中的记录映射成为对象,以对象的形式展现,程序员可以把对数据库的操作转化为对对象的操作。因此ORM的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作。 ORM 采用元数据来描述对象-关系映射细节, 元数据通常采用 XML 格式, 并且存放在专门的对象-关系映射文件中,customers,Java对象持久化概述,ORM:(Object/Relation Mapping): 对象/关系映射,域模型 (对象、属性、关联、继承和多态),ORM API ORM 实现,关系数据模型 (表、字段、索引、主键和外键),业务逻辑层,对象-关系映射文件 (xml),持久化层,数据库层,参照,ORM 充当业务逻辑层和数据库层之间的桥梁,Java对象持久化概述,ORM:(Object/Relation Mapping): 对象/关系映射 ORM中间件的使用方法 采用元数据来描述对象-关系映射细节,元数据通常采用xml格式,并存放在专门的对象-关系映射文件中。只要配置了持久化类与表的映射关系,orm中间件在运行时就能够参照映射文件的信息,把域对象持久化到数据库中。,public vid deleteCustomer(Customer c) Session session = getSession(); session.save(c); 执行步骤如下: 1.运用反射机制,获得Customer对象的Customer.class类。 2.参照映射文件得到Customer类对应的表的信息,以及和Customer类关联的类以及 相应的表信息。 3.根据以上信息生成SQL语句。 4.调用hibernate API,执行该语句。,持久化类的属性及访问方法,知识点1:Hibernate中持久化类的访问者有两个(从保存和查询两条路线看),Java应用程序不能访问持久化类的private方法,而hibernate没有这 个限制,它可以访问各种级别的方法。,持久化类的属性及访问方法,知识点2:基本数据类型和包装类型区别: 基本数据类型和包装类型对应的hibernate映射类型相同。,基本类型可直接运算、无法表达null、数字类型的默认值为0。 包装类默认值是null。当对于默认值有业务意义的时候需要使用包装类。,例如:User类有一个int类型的scope属性,表示用户的考试分数.int类型的scope属性无法表达这样的业务需求: * 如果scope的属性为null,表示该用户的成绩是未知的,有可能得了100分,也有可能得了0分,只是暂时还不知道成绩 * 如果scope属性为0,表示用户考试成绩为0分. * 在上面的情况中必须使用包装类型,持久化类的属性及访问方法,知识点3:Hibernate访问持久化类属性的策略 1.propertye 默认值:表明hibernate通过getXXX和 setXXX来访问类属性。推荐使用。提高域模型透明性。 2.field:hibernate通过java反射机制直接访问类属性。对于没有 javabean方法的属性可设置该访问策略。 3 noop:它映射Java持久化类中不存在的属性,即主要用于HQL(用query接口测试,使用hql语句)中,当数据库中有某列,而实体中不存在的情况。,持久化类的属性及访问方法,知识点4:在持久化类的方法中加入程序逻辑 在Customer.hbm.xml文件中无需映射firstname和lastname属 性,而是映射name属性。,尽管类中并没有name属性,由于hibernate不是直接访问Name属性,而是调用 get、set方法,因此建立了Firstname、Lastname和表之间的联系。,持久化类的属性及访问方法,知识点4:在持久化类的方法中加入程序逻辑 不管在类中是否存在name属性,只要在Customer.hbm.xml文件中映射了name属性,在hql语句中就能访问他。,如果改成: 后过如何? 运行出错 field name not found on com.demo.pojo.Customer,持久化类的属性及访问方法,知识点5:设置派生属性 利用元素的formula属性,用来设置一个sql表达式,hibernate将根据它来计算出派生属性的值。 在customer类中增加两个属性 * private Double price; * private Double totalprice;/在数据库中没有对应的列 在Customer.hbm.xml文件中增加如下配置 注意:在sql语句中使用别名,派生属性中使用的是sql语句,持久化类的属性及访问方法,知识点6:控制insert、update语句,处理sql引用标示符,在SQL语法中,标示符是指用于为数据库表、视图、字段或索引等名字的字符串,常规标示符不包括空格,也不包含特殊字符,因此无需使用引用符号。如果数据库表名或列名包含特殊字符,可以使用引用标示符(键盘下面的字符)。 注意:请在“英文输入法”状态下使用该符号,类中增加 private String des; 映射文件增加 ,知识点7:处理sql引用标示符,对象-关系映射基础,如果在一个映射文件中包含多个类,并且这些类位于同一个包中,可以设置元素的package属性,避免为每个类提供完整的类名。,知识点8:设置类的包名,知识点二:映射文件中的标识符,映射文件中的标识符,* Java按地址区分同一个类的不同对象. * 关系数据库用主键区分同一条记录. * Hibernate使用ID来建立内存中的对象和数据库中记录的对应关系。对象的ID和数据库的表的主键对应关系。为保证ID的唯一性,应该让Hibernate来为ID付值。(hibernate的主键策略),知识点1:唯一性的标示,映射文件中的标识符,知识点2:区分自然主键和代理主键,映射文件中的标识符,关系型数据库按主键区分不同记录 把主键定义为自动增长类型 在MySQL中,把字段设为auto_increment类型,数据库会自动为主键赋值。 在SQLServer中,把字段设为identity类型,数据库会自动为主键赋值。 oracle从序列(sequence)中获取自动增长的描述符 create sequence seq_customer increment by 1 start with 1 insert into customers values(seq_customer.nextval,),知识点3:数据库中的代理主键介绍,映射文件中的标识符,Java语言按内存地址区分不同的对象 -equals()和=方法决定引用值是否指向同一对象 equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。 Java.lang 包中的Object 类有public boolean equals (Object obj)方法。它比较两个对象是否相等。仅当被比较的两个引用指向同一对象时,对象的equals()方法返回true。 =运算符也进行等值比较。也就是说,对于任何引用值X 和Y,当且仅当X 和Y 指向同一对象时, X=Y返回真。 当两个分离的对象的内容和类型相配的话,String,Date,File 类和所有其它override equals()的包装类(Integer,Double,等等)将返回真。,知识点4:回顾java语言如何区分对象,映射文件中的标识符,ID是关系数据库中的主键在java对象模型中的等价物。在运行时,hibernate根据ID来维持java对象和数据库记录的对应关系。(session的一级缓存),Customer c1 = (Customer)session.load(Customer.class,1); Customer c2 = (Customer)session.load(Customer.class,1); Customer c3 = (Customer)session.load(Customer.class,3); c1 = c2 true c1 = c3 false 标签用来设定标示符生成器。Hibernate提供了标识符生成器接 口:org.hibernate.id.IdentifierGenerator并提供了多种内置的实现。,知识点5: Hibernate中用对象标示符(ID)来区分对象,ID和 generator属性说明,id:设定持久化类的 id 和表的主键的映射 name: 标识持久化类 id 的属性名 column: 设置标识属性所映射的数据列的列名(主键字段的名字). unsaved-value:若设定了该属性, Hibernate 会通过比较持久化类的 id 值和该属性值来区分当前持久化类的对象是否为临时对象,在Hibernate3中几乎不再需要. type:指定 Hibernate 映射类型. Hibernate 映射类型是 Java 类型与 SQL 类型的桥梁. 如果没有为某个属性显式设定映射类型, Hibernate 会运用反射机制先识别出持久化类的特定属性的 Java 类型, 然后自动使用与之对应的默认的 Hibernate 映射类型 Java 的基本数据类型和包装类型对应相同的 Hibernate 映射类型. 基本数据类型无法表达 null, 所以对于持久化类的 id 推荐使用包装类型,generator:设定持久化类的标识符生成器 class: 指定使用的标识符生成器全限定类名或其缩写名,映射文件中的标识符-主键生成策略,映射文件中的标识符,increment 标识符生成器由 Hibernate 以递增的方式为代理主键赋值 Hibernate 会先读取 NEWS 表中的主键的最大值, 而接下来向 NEWS 表中插入记录时, 就在 max(id) 的基础上递增, 增量为 1.(带走+1) 适用范围: 由于 increment 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统 适用于只有单个 Hibernate 应用进程访问同一个数据库的场合 id 必须为 long, int 或 short 类型, 如果把 id 定义为 byte 类型, 在运行时会抛出异常,知识点6: increment 标识符生成器,映射文件中的标识符,知识点7: identity 标识符生成器,identity 标识符生成器由底层数据库来负责生成标识符, 它要求底层数据库把主键定义为自动增长字段类型(加1带走) 适用范围: 由于 identity 生成标识符的机制依赖于底层数据库系统, 因此, 要求底层数据库系统必须支持自动增长字段类型. 支持自动增长字段类型的数据库包括: DB2, MySQL, MSSQLServer, Sybase 等 id 必须为 long, int 或 short 类型, 如果把 id 定义为 byte 类型, 在运行时会抛出异常,映射文件中的标识符,知识点8:sequence 标识符生成器,sequence 标识符生成器利用底层数据库提供的序列来生成标识符. Hibernate 在持久化一个 News 对象时, 先从底层数据库的 news_seq 序列中获得一个唯一的标识号, 再把它作为主键值 适用范围: 由于 sequence 生成标识符的机制依赖于底层数据库系统的序列, 因此, 要求底层数据库系统必须支持序列. 支持序列的数据库包括: DB2 Oracle id 必须为 long, int 或 short 类型, 如果把 id 定义为 byte 类型, 在运行时会抛出异常,Oralce数据库中序列的名称,映射文件中的标识符,知识点9:hilo 标识符生成器,hilo 标识符生成器由 Hibernate 按照一种 high/low 算法*生成标识符, 它从数据库的特定表的字段中获取 high 值. Hibernate 在持久化一个 News 对象时, 由 Hibernate 负责生成主键值. hilo 标识符生成器在生成标识符时, 需要读取并修改 HI_TABLE 表中的 NEXT_VALUE 值. 适用范围: 由于 hilo 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统 id 必须为 long, int 或 short 类型, 如果把 id 定义为 byte 类型, 在运行时会抛出异常,存放使用次数的表名,hi_table表的列,存放使用次数,步长,映射文件中的标识符,知识点10:native 标识符生成器,native 标识符生成器依据底层数据库对自动生成标识符的支持能力, 来选择使用 identity, sequence 或 hilo 标识符生成器. 适用范围: 由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器, 因此很适合于跨数据库平台开发 id 必须为 long, int 或 short 类型, 如果把 id 定义为 byte 类型, 在运行时会抛出异常,映射文件中的标识符,知识点11_1: assigned 标识符生成器 映射单个自然主键,映射文件中的标识符,知识点11_2: 映射自然主键 -映射复合主键 方法一,映射文件中的标识符,知识点11_3: 映射自然主键 -映射复合主键 方法二,知识点三:映射一对多关联关系,一对多关联关系,单向关联:仅仅建立从Order到Customer的多对一关联,即仅仅在Order类中定义customer属性。或者仅仅建立从Customer到Order的一对多关联,即仅仅在Customer类中定义orders集合。 双向关联:既建立从Order到Customer的多对一关联,又建立从Customer到Order的一对多关联。,单向多对一,单向一对多,双向多对一,建立多对一的单向关联关系,单向 n-1 关联只需从 n 的一端可以访问 1 的一端 域模型: 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性 关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键,ORDERS 表,CUSTOMERS 表,建立多对一的单向关联关系,Hibernate 使用 元素来映射多对一关联关系,many-to-one属性: * name:设定待映射的持久化类的名字。 * column:设定和持久化类的属性对应的表的外键。 * class:设定持久化类的属性的类型。 * not-null:是否允许为空。,建立多对一的单向关联关系,建立多对一的单向关联关系,知识点1:先保存订单,再保存客户,Hibernate的输出结果: Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?) Hibernate: insert into customers (name) values (?) Hibernate: update orders set order_number=?, price=?, customer_id=? where id=?,Jdbc执行: * insert into orders (id,order_number, price, customer_id) values (?, ?, ?,null); * insert into customers (id,name) values (?,?) * c_id=select id from customers * update orders set order_number=?, price=?, customer_id=? where id=?,建立多对一的单向关联关系,知识点2:先保存客户,再保存订单,Hibernate的输出结果: Hibernate: insert into customers (name) values (?) Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?),Jdbc执行: * insert into customers (id,name) values (?,?) * c_id=select id from customers * insert into orders (id,order_number, price, customer_id) values (?, ?, ?,cid);,建立多对一的单向关联关系,知识点3:查询订单,Hibernate的输出结果: Hibernate: select order0_.id as id1_1_, order0_.order_number as order2_1_1_, order0_.price as price1_1_, order0_.customer_id as customer4_1_1_, customer1_.id as id0_0_, customer1_.name as name0_0_ from orders order0_ left outer join customers customer1_ on order0_.customer_id=customer1_.id where order0_.id=?,Jdbc执行: SELECT * FROM customers c LEFT OUTER JOIN orders o ON(c.id=o.customer_id) WHERE o.id=2,建立多对一的单向关联关系,知识点4:先保存客户,再保存订单 在下面的代码中注释掉session.save(c),会有什么后果,产生如下异常 org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.demo.pojo.Customer,建立多对一的单向关联关系,知识点4:级联保存和更新,当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。,建立多对一的单向关联关系,建立一对多的双向关联关系,双向 1-n 与 双向 n-1 是完全相同的两种情形 双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然. 域模型:从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性 关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键,ORDERS 表,CUSTOMERS 表,建立一对多的双向关联关系,Hibernate使用set元素来映射一对多关联关系, 元素来映射持久化类的 set 类型的属性 name:设定待映射持久化类的属性名。 cascade:设定级联操作的程度。 key子属性:设定与所关联的持久化类对应的表的外键。 * column: 指定关联表的外键名 one-to-many子属性:设定所关联的持久化类(集合中存放的对象)。 * class: 指定关联的持久化类的类名,映射一对多关联关系,Hibernate要求在持久化类中定义集合属性时,必须把属性声明为接口类型,如Set、Map、List.声明为接口类型可提高持久化类的透明性,当hibernate调用setOrders()方法时,传递的参数是Hibernate自定义的实现该接口类的实例。如果定义成类(如HashSet)型,强迫hibernate把该类型的实例传给他。 底层代码: Set orders= PersistentSet class PersistentSet implements java.util.Set 通常在定义集合属性时,直接初始化为一个实现类的实例。 private Set orders = new HashSet(); 可避免空指针异常。,知识点5:定义为接口类型,建立一对多的双向关联关系,知识点6:保存客户和订单(客户和订单建立双向关联),建立一对多的双向关联关系,知识点7:保存客户和不保存订单 在下面的代码中注释掉session.save(order1),会有什么后果,产生如下异常 org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.demo.pojo.Customer,建立一对多的双向关联关系,知识点7:级联保存和更新 当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定set元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。, 元素来映射持久化类的 set 类型的属性 cascade:设定级联操作的程度。,建立一对多的双向关联关系,知识点8:查询客户和订单,Jdbc实现 select customer0_.id as id0_0_, customer0_.name as name0_0_ from customers customer0_ where customer0_.id=? select orders0_.customer_id as customer4_0_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.order_number as order2_1_0_, orders0_.price as price1_0_, orders0_.customer_id as customer4_1_0_ from orders orders0_ where orders0_.customer_id=?,建立一对多的双向关联关系,1、order1关联到customer 而customer没有关联到order1 2、customer关联到order2 order3 而order2 order3 没有关联到customer 问题 session.save(order1) 插入几条记录-4 session.save(customer) 插入几条记录-3 session.save(order2) 插入几条记录-1,知识点9:对象导航,建立一对多的双向关联关系,知识点9:对象导航,Order orderu1=new Order(); orderu1.setOrderNumber(“o_001“); Order orders2=new Order(); orders2.setOrderNumber(“o_002“); Order orders3=new Order(); orders3.setOrderNumber(“o_003“); Customer c=new Customer(); c.setName(“杨逍“); /orderu1关联c c不关联order1 orderu1.setCustomer(c); /c关联order2和order3 order2和order3不关联c c.getOrders().add(orders2); c.getOrders().add(orders3); /session.save(orders2); session.save(orderu1);,建立一对多的双向关联关系,知识点10:保持程序的健壮性 Order orderu1=new Order(); orderu1.setOrderNumber(“o_001“); Customer c=new Customer(); c.setName(“杨逍“); /订单和客户关联 orderu1.setCustomer(c); /客户和订单关联 /c.getOrders().add(orderu1); 这句话是否是可有可无的,为了保持程序的健壮性,加上 /保存客户 session.save(c); /保存订单 session.save(orderu1);,方法名(Customer c) c.getOrders().size.=0 这是在使用订单的时候就关联不上订单了 ,建立一对多的双向关联关系,更改订单表id=6的customer_id=3更改为4,上面的代码产生两条update语句 ,如何产生一条语句呢,完成上面的功能呢? Hibernate: update orders set order_number=?, price=?, customer_id=? where id=? Hibernate: update orders set customer_id=? where id=?,知识点11:订单变更客户,建立一对多的双向关联关系,更改订单表id=6的customer_id=3更改为4 * 使用session缓存的监控功能讲解为什么产生两条update语句,Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的改变来同步更新数据库,因此执行了上述的两条更新语句所以会产生两条update语句,知识点11:订单变更客户,建立一对多的双向关联关系,在hibernate中通过对 inverse 属性的值决定是由双向关联的哪一方来维护表和表之间的关系. inverse=false 的为主动方,inverse=true 的为被动方, 由主动方负责维护关联关系 在没有设置 inverse=true 的情况下,父子两边都维护父子关系 在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多) 在 1-N 关系中,若将 1 方设为主控方 会额外多出 update 语句。,知识点11:set中inverse属性,建立一对多的双向关联关系,/查询客户 Customer c4=(Customer)session.load(Customer.class, 4); /查询订单 Order o6=(Order)session.load(Order.class, 6); /建立关联关系 o6.setCustomer(c4); /c4.getOrders().add(o6); /加上和不加没有影响(不按照集合的变化来更新数据库) - 以上代码仅设置了order对象的customer属性,hibernate仍然会按照 order对象的状态的变化来同步更新数据库,执行以下sql语句: Update orders set order_number=.,customer_id=1 where id = 1,知识点11:set中inverse属性,建立一对多的双向关联关系,/查询客户 Customer c4=(Customer)session.load(Customer.class, 4); /查询订单 Order o6=(Order)session.load(Order.class, 6); /建立关联关系 /o6.setCustomer(c4); /去掉(有影响不会更新) c4.getOrders().add(o6); - 以上代码仅设置了customer对象的orders属性,由于元素的 inverse属性为true,因此,hibernate不会按照customer对象的状态 变化来同步更新数据库。,知识点11:set中inverse属性,建立一对多的双向关联关系,结论: 1.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true, 这可以提高性能。 2.在建立两个对象的关联时,应该同时修改关联两端的相应属性: customer.getOrders().add(order); order.setCustomer(customer); 这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码 不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改 关联两端的对象的相应属性: Customer.getOrders().remove(order); Order.setCustomer(null);,知识点11:set中inverse属性,建立一对多的双向关联关系,知识点12:解除关联关系,解除6号订单和3号客户的关联,建立一对多的双向关联关系,知识点13:级联删除删除1号客户的同时,删除1号客户所关联的订单,如果cascade属性取默认值none,不会自动删除和customer关联的其他持久化对象。如 果希望删除customer时,自动删除和customer关联的order对象,可把cascade属性设 为delete。 再运行删除方法的时候,会自动删除order对象,此时hibernate执行如下语句: delete from orders where customer_id = 1; delete customers where id = 1; delete from orders where id=1,建立一对多的双向关联关系,知识点14:理解什么是父子关系,所谓父子关系: 是指父方来控制子方的持久化生命周期,子方对象必须和一个父方对象关联。,Customer(父方),Order(子方),建立一对多的双向关联关系,知识点14:解除关联关系 -父子关系 解除6号订单和3号客户的关联,同时删除6号订单,/查询客户 Customer c3=(Customer)session.load(Customer.class, 3); /查询订单 Order o6=(Order)session.load(Order.class, 6); /设置订单关联的客户为null o6.setCustomer(null); /从客户集合删除订单 c3.getOrders().remove(o6); mit(); - 如果cascade为默认值none,hibernate会执行如下语句: update orders set Customer_id = null where ID = 2; 如果希望程序自动删除不再和customer关联的order对象,可以把cascade属性设为 all-delete-orphan 或 delete-orphan delete from orders where id=6,建立一对多的双向关联关系,知识点14:解除关联关系 -父子关系,当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.,cascade 属性,在对象 关系映射文件中, 用于映射持久化类之间关联关系的元素, , 和 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.,建立一对多的双向关联关系, 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序 order-by 属性中还可以加入 SQL 函数,知识点15:在数据库中对集合排序,知识点四: -操纵持久化对象 -session 缓存的问题(一级缓存) -sessionFactory 二级缓存系统级缓存,操纵持久化对象,知识点1:回顾Java对象在JVM中的生命周期,hibernate 操纵持久化对象,hibernate 操纵持久化对象,操纵持久化对象,操纵持久化对象概述,Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法.,知识点2: session概述,操纵持久化对象,在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期 当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库,知识点3:理解session的缓存,操纵持久化对象,Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为清理缓存(flush) 默认情况下 Session 在以下时间点清理缓存: 当应用程序调用 Transaction 的 commit()方法的时, 该方法先清理缓存(session.flush(),然后在向数据库提交事务(mit() 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态 显式调用 Session 的 flush() 方法.,知识点4_1:清理session的缓存,操纵持久化对象,区别: flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,; commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。 reresh:刷新,让session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态. clear:清空缓存,等价于list.removeAll();,知识点4_2:清理session的缓存,操纵持久化对象,知识点4_2:清理session的缓存,操纵持久化对象,1 Customer c = new Customer(“TOM”,new HashSet(); 2 session.save(c); /customer对象被持久化,并且加入到session的缓存中 3 Long id = c.getId(); 4 c = null; /c变量不再引用customer对象 5 /从session缓存中读取customer对象,使r2变量引用customer对象 6 Customer r2 = (Customer)session.load(Customer.class,id); 7 mit(); /缓存中的对象和数据库同步 8 session.close(); /关闭session 清空缓存 9 System.out.println(r2.getName(); /访问customer对象 10 r2 = null; /r2对象不再引用customer对象,customer对象结束生命周期 - 缓存的作用: 1。减少访问数据库的频率。 2。保证缓存中的对象与数据库中的相关记录保持同步。 3。当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循 还,以及由死循环引起的JVM内存溢出异常。,知识点4_3:清理session缓存,

温馨提示

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

评论

0/150

提交评论