Presentation is loading. Please wait.

Presentation is loading. Please wait.

对象/关系映射—Hibernate 学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际项目开发经验

Similar presentations


Presentation on theme: "对象/关系映射—Hibernate 学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际项目开发经验"— Presentation transcript:

1 对象/关系映射—Hibernate 学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际项目开发经验
作者:赵青 学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际项目开发经验 课程目标:理解O/R Mapping原理,掌握Hibernate开发的相关知识,并能使用Hibernate进行实际项目开发

2 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

3 数据的持久化 持久化持久层 持久化如何演变为持久层? 是不是只要在应用中用了数据库就天然具备了“持久层”了呢?未必!
这三种方式仅仅是实现技术的不同,在数据库上的经验和策略同样可以应用在其他的持久化方案上

4 只有持久化而没有持久层 网上商城购物结算的例子

5 如果不是这段代码的作者,谁也无法看出其中蕴含的业务逻辑,就算是代码的作者时间一长也会遗忘,恐怕要有一份十分完备的文档。

6 没有持久层的特征 业务逻辑和数据库访问逻辑混杂在一起,没有清晰的界限,干扰了我们的视线,难于理解。
业务规则的变动必然影响到数据库的访问逻辑,反之亦然,笨重,难于维护。 好处是:简单方便、开发迅速,不需要复杂的设计,比较适合于业务简单的应用。

7 引入持久层后的系统架构

8 改良后的设计

9 引入DAO模式 DAO = Data Accessor Object 数据访问对象 数据库访问的实现细节被隐藏到DAO里面。
Domain Object则提供了面向领域的对象,封装了具体的业务规则。

10 引入DAO模式的优点 业务层无需关心具体的select、insert等操作,使得业务业务逻辑实现更加清晰,也使得开发人员的专业划分成为可能,业务人员专注于业务逻辑编码。 业务层和持久层可以彼此独立的变化,比如:仅仅替换数据访问层的实现,可以将系统部署在不同的数据库平台上。

11 改良后的代码

12 观察DAO的实现细节

13 问题的症状-用JDBC实现持久层 为域中的每个类手工编写持续性代码的工作量繁重。
这些代码基本上都是“支撑性”代码,单调、机械、乏味、不优雅。 特别是需要支持多种SQL方言时,对于持久层的开发者是个大难题。

14 新需求的产生-通用的持久层框架 将编写支撑性代码的工作量降到最低。编码是有趣的工作,但是敲键盘决不有趣。凡是无趣的工作都交给机器去完成。
对象模型和关系模型的映射(ORM),编码时只需要关心对象,而无需再纠缠于JDBC ResultSet中的字段。 更好的移植性,只需要简单的修改配置参数,即可实现底层数据库的切换。

15 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

16 Hibernate在应用中的位置 基于B/S的典型三层架构 开发如何分层? 业务逻辑层和持久化层绝不要依赖于展现层。
持久层对于业务层是透明的,持久层和业务层的变化是彼此独立的。

17 Hibernate核心架构

18 Configuration Configuration 类负责管理Hibernate 的配置信息。它包括如下内容:
Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等。 Hibernate映射文件(*.hbm.xml)。 Configuration cfg = new Configuration();

19 SessionFactory 会话工厂缓存了生成的SQL语句和Hibernate在运行时使用的映射元数据。
SessionFactory sessionFactory = cfg.buildSessionFactory();

20 Session Session也称为持久化管理器,因为它是与持久化有关的操作接口。 Session代表与数据库之间的一次操作。
Session通过SessionFactory打开,在所有的工作完成后,需要关闭。 会话并不是线程安全的因此应该被设计为每次只能在一个线程中使用 。 Session session = sessionFactory.openSession();

21 Transaction (事务) Transaction将应用代码从底层的事务实现中抽象出来——可能是一个JDBC事务或一个JTA事务,这有助于保持Hibernate应用在不同类型的执行环境或容器中的可移植性。 使用Hibernate进行操作时(增、删、改)必须显示的调用Transaction(默认:autoCommit=false)。 Transaction tx = session.beginTransaction();

22 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

23 对象-关系数据库的基本映射 对象 关系数据库 public class User { private String name;
private String password; private List address; ……… } create table tbl_user ( name varchar(255) not null , password varchar(255), ………. primary key (name) ) 对象 关系数据库 记录 类的属性(基本类型) 表的列 1:n/n:1 外键

24 一个简单例子 Department.hbm.xml

25 Hibernate基本数据类型

26 实例前的准备—项目目录结构

27 insert Department dep = new Department(); dep.setName(“软件开发部”); Session s = sessionFactory.openSession(); Transaction tx = s.beginTransaction(); s.save(dep); tx.commit(); s.close();

28 Load Session s = sessionFactory.openSession(); Department dep = (Department)s.get(Department.class, depID); s.close();

29 update Session s = sessionFactory.openSession(); Transaction tx = s.beginTransaction(); Department dep = (Department)s.get(Department.class, depID); dep.setName("ggggg"); s.update(dep); tx.commit(); s.close();

30 delete Session s = sessionFactory.openSession(); Transaction tx = s.beginTransaction(); Department dep = (Department)s.get(Department.class, depID); s.delete(dep); tx.commit(); s.close();

31 使用Ant构建开发过程 Another Neat Tool 另一个整洁的工具。 ANT是一个基于Java的自动化脚本引擎,脚本格式为XML。
每个ant脚本(缺省叫build.xml)中设置了一系列任务(target),而多个任务之间往往又包含了一定的依赖关系。 Ant可以简化项目的编译、测试、文档、部署等日常工作的手工工作量。

32 进一步减少编码量-XDoclet XDoclet的灵感来自JavaDoc,JavaDoc把文档写在代码里,简化了文档与程序同步问题。
为web、ejb、struts、webwork、hibernate、jdo、jmx等等生成描述文件、源码等。 现在的XDoclet已经发展成了一个全功能的、面向属性的代码生成框架。(Attribute-Oriented Programming) UNIX业界的人们传递下来这样一个传统,就是代码是最好的文档,保持文档的同步实在是费力不讨好的事,所以他们提出这样一个好主意,不过JavaDoc更聪明,文档是程序注释的一部分,而且可以提取出来。

33 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

34 Hibernate面临的挑战:对象—关系模型的不匹配(Paradigm Mismatch)
粒度问题。(granularity) 子类型问题。(subtypes) 同一性问题。(identity) 关联问题。(associations) 对象导航问题。(navigation)

35 Identity——同一性问题 对象的同一性(identity):==是jvm定义的概念。
对象的相等性(equality):java API定义的方法。实现equals()方法。 数据库对象的同一性(identity):指向同一个表的同一个记录。

36 Database identity with Hibernate
为持久化类增加一个identifier property。 Identifier的值等于数据库中该记录的主键值,对于业务而言没有实际意义,一般该属性命名为id。 通常设置getID()为public,因为通过id查找对象会很方便,而setID()设为private,其值由hibernate产生,id不可以改变。 a == b;a.equals(b);a.getID().equals(b.getID())。

37 主键的选择 natural keys:从业务意义上寻找一个或者多个属性来区分唯一性,和是否是自动产生的无关。业务逻辑和数据逻辑位于不同的层面,应该有清晰的界定,不要把业务逻辑牵扯到数据逻辑中,否则业务逻辑的变化将对数据逻辑产生根本的影响。 synthetic identifiers(surrogate keys):surrogate keys 没有业务含义,它是由数据库或者应用产生的。 composite keys:多个natural keys联合组成的primary key。历史的遗留系统无法避免。

38 identifier generator——主键生成策略
<id name="departmentID" column="department_id" type="long" > <generator class=“native"></generator> </id> native:hibernate将根据底层数据库的方言(Dialect)来选择,SQLServer用identity,Oracle用sequence等。

39 increment:主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。应用于single-server的环境下特别高效,如果被部署成多个应用的环境,会造成主键重复错误。 uuid.hex:用一个128-bit的UUID算法生成字符串类型的标识符。使用了IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。用该算法生成的id可以确保在一个网络中唯一。适用于多应用的环境,即使在多实例并发的环境中也可以确保唯一。并且解决了多个数据库的部分数据合并。

40 granularity——粒度问题 fine-grained object model 适当的细粒度对象模型:所谓细粒度模型,就是将原本业务模型中的对象加以细分,从而得到更加精细的对象模型。

41 细粒度模型的设计 该设计体现了一个“合成 ”的关系(composition):即整体和部分的关系。部分不可独立存在而依赖于整体。
sendMessage() 这种细粒度的设计更好的体现了类的内聚性,体现了对象设计的职责分配原则:将职责分配给拥有履行一个职责所必需信息的类 。

42 数据库设计的思考 这样的设计是不必要的,并且存在性能问题。

43 Entity and Component 在Java中不存在实体类和component类的区别,所有类的含义都是相同的。
Entity类有数据库的主键值, Entity类有自己的生命周期,它不依赖于其他的类而独立存在。 component类没有相应的主键值,它从属于Entity,它的生命周期从属于Entity,随着Entity的消亡而消亡。 component类也称value type。

44 映射文件的格式

45 Subtypes——子类型问题 对象模型存在“is a”和“has a”的关系,而关系模型仅仅存在“has a”的关系,这是对象模型和关系模型最明显的mismatch,如何将“is a”转化为数据库中的“has a”是hibernate需要解决的问题。

46 Table per concrete class
这是最简单的一种方式:每一个子类对应一张表,父类没有表。 这种方式会产生“Polymorphic queries”的问题。

47 Polymorphic queries—多态查询
对于父类的查询需要运行多条select语句,每个子类一条。 select CREDIT_CARD_ID, OWNER, NUMBER, CREATED, TYPE, ...from CREDIT_CARDwhere CREATED = ? select BANK_ACCOUNT_ID, OWNER, NUMBER, CREATED, BANK_NAME, ...from BANK_ACCOUNT where CREATED = ? 父类的变动困难:父类的变动会影响所有的子类属性,从而会影响多个表中的字段。 仅仅用在不需要多态查询的场合。

48 Table per class hierarchy
整个继承树对应一张表,子类用type discriminator字段来区分。这种方式在性能和简单性两方面都做的很好。 父类的变动很方便。

49 多态查询 查询父类 select BILLING_DETAILS_ID, BILLING_DETAILS_TYPE,OWNER, ..., CREDIT_CARD_TYPE, from BILLING_DETAILS where CREATED = ? 查询子类 select BILLING_DETAILS_ID,CREDIT_CARD_TYPE,CREDIT_CARD_EXP_MONTH, ...from BILLING_DETAILS where BILLING_DETAILS_TYPE='CC' and CREATED = ? problem:子类属性对应的column不可以有not null的约束。

50 映射文件的格式

51 Table per subclass 这种设计符合数据库的设计范式。 但是可能会有严重的性能问题。

52 多态查询的解决——父类 查询父类:用outer join

53 多态查询的解决——子类 查询子类:用inner join 这种方式如果用手工写代码完成则很困难。
查询需要关联多张表,对于复杂的继承树结构,性能是个大问题。

54 映射文件格式

55 继承策略选择 一般原则:如果你不需要多态查询,可以考虑用table-per-concrete-class,如果你需要多态查询,并且子类的属性差异不大,考虑用table-per-class-hierarchy,但是如果子类的属性差异很大,考虑用table-per-subclass。 经验:对于一般的解决,尽量用table-per-class-hierarchy, table-per-subclass请慎重使用。

56 associations—关联 对象之间通过reference和reference集合来关联,而关系模型则通过外键进行关联。
对象模型存在多对多的关系,而关系模型只有one-to-many和one-to-one。如果关系模型要实现多对对,需要一个link table,而这个link table不存在于对象模型中。

57 many to one

58 one to many

59 双向关联产生的问题 在内存中有两个不同的地方代表同一个值:即外键item_id
如果我们调用了bid.setItem(item);bids.add(bid); hibernate会认为是两个不同的持久类发生了变动,它并不知道这两个变动实际上是指向同一个数据库的字段,hibernate会更新两次。 我们需要告诉hibernate这是一个双向的关联。

60 主控方和被控方 inverse=“true”即告诉 hibernate对方是主控方。 由bid端负责保持和 数据库的同步。
如果调用bids.add(bid);则不发生任何持久化动作,只有调用了bid.setItem(item);才持久化。 原则:应该将many端设为主控方,这样有助于改善性能。

61 cascading save 当我们把bid加入到item, 并且把item持久化的时候, 我们希望bid能够自动的 持久化,而不用显示的去调用。 cascade属性告诉hibernate bid可以被级联持久化。 cascade是有方向性的,也可以在bid端设置级联持久化item,但是因为bid是在item后创建的,这样做没有意义。

62 cascading delete Item 和bid应该是父子关系,item如果被删除,bid也应被删除。子对象的生命周期依赖于父对象。
这类似于Entity/Component的关系,但是有本质的区别。Bid可以单独的被加载,而component不能;bid可被共享而component不能。 bid如果被item内的集合删除,则应该在持久化层被删除。

63 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

64 对象的持久生命周期 持久类和一般类只有概念上的区别,从代码上看没有区别,持久类不知道自己的持久状态,所有的业务逻辑也与对象是在内存中还是在数据库中无关。 内存中的对象只有两种状态:有用和无用。 Hibernate通过session来控制对象的持久生命周期:transient,persistent, detached.

65 Transient objects new生成的对象称为Transient,它没有与数据库中的某一行记录关联,一旦它被dereferenced就会被JVM回收。 hibernate认为所有的transient对象都是非事务的,hibernate不提供对这些对象的回滚支持。 仅仅被transient对象reference的对象也是transient对象。

66 Persistent objects persistent对象对应数据库的一条记录,并且具有database identity。
对于transient对象,调用session.save()可以将其转变为persistent object。如果通过session.load()加载一个对象,该对象也是persistent状态。 hibernate对persistent对象提供与数据库的同步支持和事务支持。

67 与数据库的同步 脏数据:数据仅仅在内存中更新而没有同步到数据库中称为脏数据。
hibernate会监测脏数据,在尽可能迟的时候做同步的动作。(transparent transaction-level write-behind) hibernate可以做到仅仅更新有变动的属性,但是需要在映射文件中设置dynamic-update=“true”,默认是false。这个功能用手工很难完成。

68 Detached objects 当调用session.close(),原先的persistent object就转化为detached object。 detached object和数据库失去了联系,但是它们不是transient object,它们具有datebase identity。 hibernate可以在新的事务中重新联系detached object。这样可以在多个层面中传递这些持久对象。对于多层架构的设计产生重大影响。

69 例子——1

70 例子——2

71 例子——3

72 对象的状态图

73 区分transient and detached对象
Identifier属性是否为null 对于非对象类型的Identifier,判断unsaved-value的值 优先考虑使用对象类型的Identifier,因为对象可以为null。 该方法只对synthetic keys有效,对于assigned keys和composite keys无效。

74 The scope of object identity
no identity scope:数据的同一性没有范围,同一条记录分别取两次,返回的对象不满足a==b; transaction-scoped identity:在同一个事务中,同一条记录取两次,满足a==b,在事务级别需要缓存; Process-scoped identity:在同一个进程中只有一个对象被返回,范围达到整个JVM。

75 对象树 通常大型应用中操作的不可能只有一个对象,而是一个对象图。

76 Persistence by reachability
compute被持久化时,它所reference的任何对象都被持久化,但是不包括“Electronics” 和 “Cell Phones”。 这是一个递归的过程。 在理想的环境中:root对象被加载,那么整个对象树在任何时候都可以被重新建立。如果某一个对象是非reachable的,那么就应该成为transient。

77 不可能的任务 数据库没有root的概念,只有foreign key。 Java有垃圾回收的算法,而数据库没有。
如果数据库要实现一个类似的,需要做全表扫描,那时不现实的。 对象图只是数据库的一部份。 persistence by reachability只解决了一半问题,如何完成persistence -> transient。

78 解决之道—Cascade none:默认设置,hibernate不做级联任何动作。
save-update:如果item被持久化,那么所有被item所reference的bid都应该被持久化。 delete:如果item被删除,那么item所reference的bid的被删除。 all:= save-update + delete delete-orphan:如果Item所属的Bid Set中的某个Bit被删除, 那么数据库中Bid也被删除.

79 目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子
目 录 持久层的概念及必要性 hibernate框架及核心类介绍 hibernate进行持久化的一个例子 hibernate如何解决对象和模型的不匹配 对象的持久性生命周期 对目前项目的进一步封装和思考

80 重新思考项目之间的关系

81 etong-common的依赖关系

82 etong-common的内部体系

83 持久包—通用的持久化类设计

84 优化设计后的代码 User user = new User(); user.setName(name); user.setPassword(password); user.set ( ); PersistenceFactory.getInstance().makePersistent(user);

85 沉重的反思——事务脚本 粒度顺序是:service > dao > domain
业务逻辑尽量写在domain里,不要在service写任何业务逻辑,而仅仅在service里调用dao和domain,完成事务逻辑,供前台调用。

86 参考书籍 Hibernate In Action——CHRISTIAN BAUER、GAVIN KING
Patterns of Enterprise Application Architecture (企业应用架构模式)——Martin Fowle 深入浅出Hibernate——夏昕、曹晓钢


Download ppt "对象/关系映射—Hibernate 学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际项目开发经验"

Similar presentations


Ads by Google