




已阅读5页,还剩24页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
一、预备知识对于Hibernate,它的对象有三种状态,transient、persistent、detached下边是常见的翻译办法:transient:瞬态或者自由态(new DeptPo(1,”行政部”,20,”行政相关”),该po的实例和session没有关联,该po的实例处于transient)persistent:持久化状态(和数据库中记录想影射的Po实例,它的状态是persistent, 通过get和load等得到的对象都是persistent)detached:脱管状态或者游离态(1) 当通过get或load方法得到的po对象它们都处于persistent,但如果执行delete(po)时(但不能执行事务),该po状态就处于 detached, (表示和session脱离关联),因delete而变成游离态可以通过save或saveOrUpdate()变成持久态(2) 当把session关闭时,session缓存中的persistent的po对象也变成detached,因关闭session而变成游离态的可以通过 lock、save、update变成持久态,持久态实例可以通过调用 delete()变成脱管状态。通过get()或load()方法得到的实例都是持久化状态的。脱管状态的实例可以通过调用lock()或者 replicate()进行持久化。save()和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE,而update()或merge() 会引发SQL UPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQL UPDATE。saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE。有了这些预备知识,便可以对不同的Hibernate保存方式惊醒比较了。二、save 和update区别把这一对放在第一位的原因是因为这一对是最常用的。save的作用是把一个新的对象保存。update是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库。三、update 和saveOrUpdate区别这个是比较好理解的,顾名思 义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用Hibernate reference中的一段话来解释他们的使用场合和区别,通常下面的场景会使用update()或saveOrUpdate(): 程序在第一个session中加载对象,接着把session关闭 该对象被传递到表现层 对象发生了一些改动 该对象被返回到业务逻辑层最终到持久层 程序创建第二session调用第二个session的update()方法持久这些改动 saveOrUpdate(po)做下面的事: 如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事 如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常 org.Hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: org.itfuture.www.po.Xtyhb#5saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象 四、persist和save区别这个是最迷离的一对,表面上看起来使用哪个都行,在Hibernate reference文档中也没有明确的区分他们.这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别)主要内容区别:1,persist把一个瞬态的实例持久化,但是并不保证标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。2,save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert五、saveOrUpdate,merge和update区别比较update和merge,update的作用上边说了,这里说一下merge的,如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例:(1)当我们使用update的时候,执行完成后,会抛出异常。 (2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态。六、flush和update区别这两个的区别好理解,update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象/updateSQL而flush是操作的在持久状态的对象。默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待Hibernate flush就自动更新或保存到数据库了。Hibernate flush发生在以下几种情况中:1,调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合get()一个对象,把对象的属性进行改变,把资源关闭。2,transaction commit的时候(包含了flush)七、lock和update区别update是把一个已经更改过的脱管状态的对象变成持久状态,lock是把一个没有更改过的脱管状态的对象变成持久状态(针对的是因Session的关闭而处于脱管状态的po对象(2),不能针对因delete而处于脱管状态的po对象)对应更改一个记录的内容,两个的操作不同:update的操作步骤是:(1)属性改动后的脱管的对象的修改-调用updatelock的操作步骤是:(2)调用lock把未修改的对象从脱管状态变成持久状态-更改持久状态的对象的内容-等待flush或者手动flush八、clear和evcit的区别clear完整的清除session缓存evcit(obj)把某个持久化对象从session的缓存中清空。以上便是对比较难以区分的不同的Hibernate保存方式进行的比较。Hibernate映射关系:自动生成表:说这些是为了下面我们会使用Hibernate的一个类来为我们生成表。而不需要手动建表了:public class CreateTable public static void main(String args) Configuration config = new Configuration().configure(); System.out.println(通过映射文件生成数据库的表); SchemaExport se = new SchemaExport(config); se.create(true, true); System.out.println(完成生成数据库表);1、老师学生:单向在同一课堂内,有N个学生,只有1个老师,所以学生对老师是单向的多对一,也可以做成双向的,但是这样就会有数据的冗余,再本章节最后才会说明双向关联首先是老师的pojo类:public class Teacher private Integer id; /ID,标识符 private String teacherName; /教师的名字 .省略getter、setter和构造方法学生的pojo类:public class Student private Integer id; /ID,唯一标识符 private String studentName; /学生的名字 Teacher teacher; /教师类对象 .省略getter、setter和构造方法创建教师类的映射文件 Teacher.hbm.xml,没什么特别,没有任何关联关系的描述 创建学生类的映射文件Student.hbm.xml 在上述的xml中标签说明存在一个多对一的映射关系,多对一的属性为Student类中的teacher属 性(name的值),对应表中的列名为teach_id(column的值),映射关系另一方的类为Teacher类,这里需要写类全名,包括包名 (class的值),lazy为延迟加载,俗称懒的初始化,为true时,在select 学生对象时,不会加载Teacher类对象,当需要一对一的关联关系时,红字部分为必须的,保证关系方的唯一性。在多对一的时候unique则为 false2、多对一:反过来关联,一个老师对应多个学生的单向关联,一对多的关联关系如下:首先是老师的pojo类:public class Teacher private Integer id; /ID,标识符 private String teacherName; /教师的名字private Set students = new HashSet(); /学生的集合 .省略getter、setter和构造方法学生的pojo类:public class Student private Integer id; /ID,唯一标识符 private String studentName; /学生的名字 .省略getter、setter和构造方法学生类的映射关系描述文件:没什么特别 教师类的映射关系描述文件:Teacher.hbm.xml 关于标签中的各个元素:name:需要描述映射关系的类属性名inverse:反转,默认为false,当为false的时候每次更新一次被关联方,就会再次更新一次关联方数据fetch:指定了关联对象抓取的方式是select查询还是join查询,select方式时先查询返回要查询的主体对象(列表),再根据关联外 键id,每一个对象发一个select查询,获取关联的对象,形成n+1次查询;而join方式,主体对象和关联对象用一句外键关联的sql同时查询出 来,不会形成多次查询。如果关联的对象lazy=true,它不会去查询关联对象。(通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中,使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。 在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。 ):Student类对应表的关联外键为teacher_id:关联对方的class类型为:这里要类全名,包括包名。一对多(多对一)的双向关联:就是把上述两种关联方式结合起来。老师的POJO类:public class Teacher private Integer id; /ID,标识符 private String teacherName; /教师的名字private Set students = new HashSet(); /学生的集合 .省略getter、setter和构造方法学生的POJO类:public class Student private Integer id; /ID,唯一标识符 private String studentName; /学生的名字 Teacher teacher; /教师类对象 .省略getter、setter和构造方法教师类的映射关系描述文件:Teacher.hbm.xml 学生类的映射文件Student.hbm.xml 注意的是,不能在双方同时指定级联操作cascade=save-update,这样会产生一个org.hibernate.ObjectDeletedException。因为删除操作也是属于update操作,在删除时,会激发关联的save方法,这是不允许的。+多对多多对多在大多数应用中还是以一张中间表,以及其pojo类拆分成两个1对多来解决.但是偶尔也会使用中间表并不使用中间表的pojo进行多对多的映射还是以Student和Teacher两个类做例子.先介绍下多对多不使用中间POJO类的方法:单向关联:public class Student private Integer id; /ID,唯一标识private String studentName; /学生姓名private Set teachers = new HashSet(); /关系集合.省略getter、setter以及构造方法public class Teacher private Integer id; /ID,唯一标识private String teacherName; /教师姓名.省略getter、setter以及构造方法映射文件Student.hbm.xml: 说明里的子标签,key标签表明了在studentTeacher表中引用当前类对应表的主键的外键名。换句话说,表明了 studentTeacher里哪一列引用了当前类对应表的主键,标签说明多对多关系的另一方是哪个类,关系表 中哪一列引用了另一方的主键。Teacher.hbm.xml: 双向关联:下面的POJO类都省略了getter和setter以及构造方法教师POJO类:public class Teacher private int id;private String teacherName;private Set students;学生POJO类:public class Student private int id;private String studentName;private Set teachers = new HashSet();教师映射文件Teacher.hbm.xml 学生映射文件Student.hbm.xml 多对多使用中间POJO类的方法:这里只介绍双向关联的映射方法,太饿了。老婆还没回来。没心思写了中间POJO类:StudentTeacher类public class StudentTeacher private Integer id;private Teacher teacher;private Student student;private int score;.省略了getter、setter以及构造方法这时Teacher和Student的pojo类内的集合里应该放置这个中间类对象的集合了public class Teacher private Integer id;private String teacherName;private Set studentTeachers = new HashSet();.省略了getter、setter以及构造方法public class Student private Integer id;private String studentName;private Set studentTeachers = new HashSet();.省略了getter、setter以及构造方法下面是他们的映射文件,其实就是2个双向的1对多。前面那篇文章已经说过了Student.hbm.xml: Teacher.hbm.xml StudentTeacher.hbm.xml: 其实很简单的。Company与Employee类之间为一对多多态关联关系,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么就能映射Company类的 employees集合。本节介绍如何映射多对一多态关联。如图14-11所示,ClassD与ClassA为多对一多态关联关系。图14-11 ClassD与ClassA为多对一多态关联关系ClassA、ClassB和ClassC构成了一棵继承关系树,如果继承关系树的根类对应一个表,或者每个类对应一个表,那么可以按以下方式映射ClassD的a属性:假定与ClassD对应的表为TABLE_D,与ClassA对应的表为TABLE_A,在TABLE_D中定义了外键A_ID,它参照TABLE_A表的主键。 ClassD对象的a属性既可以引用ClassB对象,也可以引用ClassC对象,例如: tx = session.beginTransaction();ClassD d=(ClassD)session.get(ClassD,id);ClassA a=d.getA();if(a instanceof ClassB) System.out.println(ClassB)a).getB1();if(a instanceof ClassC) System.out.println(ClassC)a).getC1();mit();以下代码在映射ClassD类的a属性时使用了延迟检索策略:当Hibernate加载ClassD对象时,它的属性a引用ClassA的代理类实例,在这种情况下,如果对ClassA的代理类实例进行类型转换,会抛出ClassCastException: ClassA a=d.getA();ClassB b=(ClassB)a; /抛出ClassCastException解决以上问题的一种办法是使用Session.load()方法: ClassA a=d.getA();ClassB b=(ClassB)session.load(ClassB.class,a.getId();System.out.println(b.getB1();当执行Session的load()方法时,Hibernate并不会访问数据库,而是仅仅返回ClassB的代理类实例。这种解决办法的前提条件是必须事先知道ClassD对象实际上和ClassA的哪个子类的对象关联。 解决以上问题的另一种办法是显式使用迫切左外连接检索策略,避免Hibernate创建ClassA的代理类实例,而是直接创建ClassA的子类的实例: tx = session.beginTransaction();ClassD d=(ClassD)session.createCriteria(ClassD.class) .add(Expression.eq(id,id) .setFetchMode(a,FetchMode.EAGER) .uniqueResult();ClassA a=d.getA();if(a instanceof ClassB) System.out.println(ClassB)a).getB1();if(a instanceof ClassC) System.out.println(ClassC)a).getC1();mit();如 果继承关系树的具体类对应一个表,为了表达ClassD与ClassA的多态关联,需要在TABLE_D中定义两个字段:A_ID和 A_TYPE,A_TYPE字段表示子类的类型,A_ID参照在子类对应的表中的主键。图14-12显示了表TABLE_D、TABLE_B和 TABLE_C的结构。图14-12 表TABLE_D、TABLE_B和TABLE_C的结构由于关系数据模型不允许一个表的外键同时参照 两个表的主键,因此无法对TABLE_D表的A_ID字段定义外键参照约束,而应该通过其他方式,如触发器,来保证A_ID字段的参照完整性。由于 TABLE_D表的A_ID字段既可能参照TABLE_B表的ID主键,也可能参照TABLE_C表的ID主键,要求TABLE_B表和TALBE_C表 的ID主键具有相同的SQL类型。在ClassD.hbm.xml文件中,用元素来映射ClassD的a属性:元素的meta-type属性指定TABLE_D中A_TYPE字段的类型,id-type属性指定TABLE_D中A_ID字段的类型,子 元素设定A_TYPE字段的可选值。在本例中,如果A_TYPE字段取值为B,表示为ClassB的对象,A_ID字段参照TABLE_B表中的ID 主键;如果A_TYPE字段取值为C,表示为ClassC的对象,A_ID字段参照TABLE_C表中的ID主键。子元素指定TABLE_D表中的A_TYPE字段和A_ID字段,必须先指定A_TYPE字段,再指定A_ID字段。 小结 本章介绍了映射继承关系的三种方式: 继承关系树的每个具体类对应一个表:在具体类对应的表中,不仅包含和具体类的属性对应的字段,还包含和具体类的父类的属性对应的字段。这种映射方式不支持多态关联和多态查询。 继承关系树的根类对应一个表:在根类对应的表中,不仅包含和根类的属性对应的字段,还包含和所有子类的属性对应的字段。 这种映射方式支持多态关联和多态查询,并且能获得最佳查询性能,缺点是需要对关系数据模型进行非常规设计,在数据库表中加入额外的区分各个子类的字段,此外,不能为所有子类的属性对应的字段定义not null约束。 继承关系树的每个类对应一个表:在每个类对应的表中只需包含和这个类本身的属性对应的字段,子类对应的表参照父类对应的表。 这种映射方式支持多态关联和多态查询,而且符合关系数据模型的常规设计规则,缺点是它的查询性能不如第二种映射方式。在这种映射方式下,必须通过表的内连接或左外连接来实现多态查询和多态关联。 在默认情况下,对于简单的继承关系树可以采用根类对应一个表的映射方式。如果必须保证关系数据模型的数据完整性,可以采用每个类对应一个表的映射方式。对于复杂的继承关系树,可以将它分解为几棵子树,对每棵子树采用不同的映射方式。当然,在设计域模型时,应该尽量避免设计过分复杂的继承关系,这不仅会增加把域模型映射到关系数据模型的难度,而且也会增加在Java程序代码中操纵持久化对象的复杂度。对于不同的映射方式,必须创建不同的关系数据模型和映射文件,但是域模型是一样的,域模型中的持久化类的实现也都一样。只 要具备Java编程基础知识,就能创建具有继承关系的持久化类,因此本章没有详细介绍这些持久化类的创建过程,在此仅提醒一点,子类的完整构造方法不仅负 责初始化子类本身的属性,还应该负责初始化从父类中继承的属性,例如以下是HourlyEmployee类的构造方法:public class HourlyEmployee extends Employeeprivate double rate; /* 完整构造方法*/public HourlyEmployee(String name, double rate,Company company) super(name,company);this.rate=rate;/* 默认构造方法*/public HourlyEmployee() Hibernate只会访问持久化类的默认构造方法,永远不会访问其他形式的构造方法。提供以上形式的完整构造方法,主要是为Java应用的编程提供方便基础Hibernate的类通用:package org.ets.criterion.dao;import java.io.Serializable;import java.util.Collection;import java.util.List;import org.ets.criterion.domain.DomainObject;/* * Interface for generic DAO operations * * author Terry */public interface Dao
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论