`

深入理解O/R Mapping

阅读更多

什么是O/R Mapping?

广义上,ORM指的是面向对象的对象模型和关系型数据库的数据结构之间的相互转换。

狭义上,ORM可以被认为是,基于关系型数据库的数据存储,实现一个虚拟的面向对象的数据访问接口。理想情况下,基于这样一个面向对象的接口,持久化一个OO对象应该不需要要了解任何关系型数据库存储数据的实现细节。

为什么需要O/R Mapping?

广义上,因为我们需要面向对象来描述我们的业务,我们也需要关系型数据库来存储我们的数据。

有人可能会提到,我们未必要用面向对象来描述业务,或者未必用关系型数据库来存储数据。没错,但是,至少,还是有相当大部分的程序,同时需要这两者的合作。存在即合理。因为同时需要彼此,两者都客观存在,就值得讨论。

既然从广义上,存在即合理,无需讨论为什么需要ORM,很多关于ORM的讨论,其实都是针对上面提到的狭义的定义。但是即使到目前为止,真正能够完美的实现这个狭义定义的ORM的工具,其实还并不存在(很多工具如Hibernate,已经相当接近,但是,离完美还有相当距离)。

既然还不存在,那么,在讨论需不需要之前,我们恐怕要先讨论一下,是否可能,即从理论上,从数学上,面向对象的对象模型和关系型数据库的数据结构之间,到底能不能做到完美的映射?要回答这个问题,我们要解决两个难题。

O/R阻抗失衡

第一个难题,叫“O/R阻抗失衡(O/R Impedance Mismatch)”,指的是OO对象模型和关系型数据库的数据结构之间的,设计理念上的差异。OO的设计理念,是以最正确的语义来描述真实世界;而关系型数据库的设计理念,则是从数学的角度,如何更有效的存储和管理数据。由于两者设计理念的差异,导致它们尽管从数据结构上,可能很相近,但是关注点往往是不同的。

 

例如:

  • 从OO的角度,凡是语义明确,每一个对象语义上的属性,就应该定义为一个属性;从关系型数据库的角度,有可能考虑到一些属性从来不会被作为查询条件,而把多个语义上的属性,以一定的格式,存在一个数据表的字段中,也有可能因为一组语义上的属性使用的频度完全不同与另一组属性,即使他们语义上属于一个对象,也有可能将他们拆分成两个数据表来存储。
  • 从OO的角度,对象只关心自己的固有属性,不需要被唯一标识;但是,从关系型数据库的角度,一般一个数据表中的每一行数据都需要要一个唯一标识,且很可能是语义上没有意义的,如自增长的标识。
  • 从OO角度的优化,一般遵循SOLID这样的原则,以更正确的语义来组织对象;从关系型数据库角度的优化,往往为了查询性能,来修改字段的类型、长度,修改索引,甚至分表、分库。
  • ...

一个ORM工具想要通过简单的配置,完美的解决“O/R阻抗失衡”问题,在我看来几乎是不可能的。但是,一定程度上,通过灵活的配置支持绝大多数常见的映射策略,再加上提供可供用户通过自定代码来扩展的接口的话,应该还是可以相当接近完美的。

文化阻抗失衡

第二个难题,叫“文化阻抗失衡(Cultural Impedance Mismatch)”,指的是关系型数据专家和面向对象专家之间的文化差异。关于这个难题的最经典的争论是“到底应该以关系型数据库的数据结构来驱动,还是以OO的对象模型来驱动程序的开发?”。

 

关于这个争论,OO专家的主要观点是:
我的业务才是程序的核心,数据库只是为我持久化数据的需求服务的,所以设计OO对象模型的时候,我不应该考虑如何存储到关系型数据库的问题;

 

而数据库专家的主要观点是:
数据才是公司的核心财富,数据的稳定性远远强于OO对象模型的稳定性,由OO对像模型来驱动数据库架构的设计,根本保证不了性能,数据库维护的成本根本不可接受。

 

其实,争论的真正原因即在于“关系型数据专家和面向对象专家之间的文化差异”。大大牛Scott W. Ambler的文章Why Data Models Shouldn't Drive Object Models(And Vice Versa),很好的解答了这个问题。

 

归根结底,既然OO和关系型数据库都是不可缺少的部分,需要协同工作,希望做到完美的ORM,不仅仅需要好的ORM工具,更需要无论是OO专家还是数据库专家互相了解对方的技术和设计理念。对一个OO专家,一个ORM工具,可以对其所支持的常见的映射,提供直接的支持,但是,应用这些ORM工具的OO专家,必须了解关系型数据库,知道如何在不影响OO对象的语义的前提下,如何设计一个更容易映射到关系型数据库的对象模型,知道如何选择ORM工具所支持的映射方式,以及如何用自定代码扩展ORM所不能方便支持的映射方式;同样的,对一个关系型数据库的专家,也需要了解OO的语义,和可能发生的重构,从而,使得所设计的数据库结构,更容易映射到OO对象,更容易响应OO对象模型的重构。如此才是真正的和谐,真正的完美。

小结

综上所述,无论对一个OO专家还是对一个关系型数据库专家,都需要了解OO,并了解关系型数据库,了解ORM的基本原理。离开全面的知识,一个再完美的ORM工具也无法被正确使用,拥有这些知识,则能够充分利用已有的ORM工具来加速自己的工作,并且合理的或扩展现有的ORM工具,或用自定代码,实现ORM工具能力之外的ORM映射。这才是理想的ORM实践。下一章节,我们就来谈谈一下,ORM的基本原理。

如何进行O/R Mapping?

简单映射

1. Class <-> Table

一个Class一般可以映射为一个Table,一个Class的实例对应Table的一行数据。但是,一个Table中的每行数据,一般都需要有一个主键来唯一标识这行数据,而一个Class的每个实例,则不一定需要一个唯一标识。

2. Property <-> Field

一个Class的Property一般可以直接映射为Table的一个Field。但是,他们的数据类型不一定直接匹配。如果他们代表的数据类型的语义上可转换,则Field的类型,应大于等于Property的数据类型。如果他们代表的类型语义上不可转换,则需要在应用程序层面,进行自定义的转换。

继承映射

1. 单表映射整个继承体系

用一张数据库表存储整个继承体系中的所有Class的数据,数据表需要额外的标志字段来区分一行记录应该映射到继承体系中的哪一个Class,适合继承体系层次较少,总记录数相对较少,子类对父类的属性扩展也相对不那么频繁的情形。

单表映射整个继承体系的优点是读/写继承体系中的每个Class的数据,都只需操作一张表,性能较好,并且,新增继承类,或扩展Class属性都只需要增减一张表的字段就可以了,易于维护;主要缺点是,因为继承体系中所有的Class共享一张表,表中会有比较多的NULL字段值的数据,浪费了一些存储空间,同时,如果记录数过多,表就会更庞大,也会影响表的读写性能。

 

2. 一个Class映射一个具体表

所谓一个Class映射一个具体表就是每个Class对应一张数据表,并且,每个数据表冗余包含其父类的所有属性字段,并且,子类和父类共享相同的主键值。一个Class一个具体表方案适合需要较高查询性能,继承体系层次不太复杂,并且基类包含较少的属性而子类扩展较多属性,并且能够承受一定的数据库冗余的情况。

一个Class映射一个具体表方案的优点主要就是查询性能好,读操作只需操作一张表,和实体数据的对应结构清晰,数据库表迁移和维护会比较方便;主要的缺点是数据冗余较大,因为每次插入一条子类数据时,同时要插入一份子类包含的父类字段的数据到所有父类层次表中。

 

3. 一个Class映射一个扩展表

所谓一个Class映射一个扩展表是指继承体系中的每个Class对应一张数据表,但是,每个子类不冗余包含父类的所有属性,而只是包含扩展的属性和共享的主键值。一个Class映射一个扩展表方案适合继承体系非常复杂,结构易变,并希望最大程度减少数据冗余的情形。

一个Class映射一个扩展表方案的优点是结构灵活,新增子类或插入中间的继承类都很方便,冗余数据最少;但是缺点是,无论读还是写操作都会涉及到子类和所有的父类。读操作时,必须自然链接查询所有的父类对应的数据表,而插入或更新数据时,也需要写所有的父类表。

 

4. 通用的表结构映射所有的Class

这种方案其实不仅支持用一张表存储一个继承体系,它甚至可以支持,用一张表存储任意数量的不同Class。它的原理是元数据驱动。这张表的每一行,包含一个类型的标识字段,一个表示Class的属性名称的字段和一个表示Class的属性值的字段。在运行时,通过唯一标识取出描述一个Class实例的所有Property的值,再根据Property的名称来映射。

 

关联映射

1. 一对一关联、一对多关联(包含一对一和一对多的自关联)

所谓一对一关联,实际上还可以分为三种情形,即0..1 - 1,1 – 1,1 – 0..1三种情形;而一对多关联则分为* - 1和1 - *。

以下三种方案中第1)种为最常用的映射方案,后面几种是在某些特殊情形下可参考的方案:

1) 最常用的方案为为需要其他对象引用的类对应的表增加一个到被引用对象对应表的外键即可,只不过,与表对应的实体类代码中,对于一对多情形下的“多”这一端,需定义成集合类型;
2) 在Hibernate称为“组件(Component)映射”,举例来说,假如Person类包含一个Address成员类型的属性,而Address由City,Street,ZipCode三个成员属性组成,假如Address除了与Person关联不被其他对象使用,则我们可以考虑只用一张数据表Person来持久化Person和Address这两张表,Person数据表包含Person类中除Address的属性和Address类中的所有属性的集合,当然,这时需要在元数据中特别指明映射关系;
3) 还有一种针对上面的方案中的Person,Address两个类的持久化方案则是将Address类型的所有属性先序列化,再存入Person表的字段Address中,这样也可以只用一张表来持久化两个类,当然,本方案中这种被序列化对象成员数据量应尽量小;
4) 还有一种方案是共享同一主键值的一对一关联。即将原本可以同属于一个表中相对使用不太频繁的字段提出来放在另一张表中,这样,这两张表的记录就可以通过一个相同的主键进行关联。

 

2. 多对多关联(包含多对多的自关联)

所谓多对多关联自然就是* - *这种情形了。一般都需要一张包含关联双方主键的关联表,在取数据时,需要链接该关联表和数据表

分享到:
评论
10 楼 p_x1984 2011-01-17  
关键地方是在写东西的时候深入的体会这些点。
9 楼 mqlfly2008 2011-01-17  
看了这个,再去看看牛人写的hibernate中几种状态的切换,hibernate基本就只差实战了
8 楼 mfkvfn 2011-01-07  
内容与标题相关太远。
7 楼 kyfxbl 2011-01-06  
。。。这不就是在翻译《java persistance with hibernate》的chapter1吗?
6 楼 rmn190 2011-01-06  
“文化阻抗失衡”,不错的名字, 这段时间体会到这个问题了,不过一直没有想出一个词来概括。
5 楼 phrmgb 2011-01-05  
原理讲的不错,要是例子在多举些就好了
4 楼 p_x1984 2011-01-05  
回过头来复习以前的知识。
3 楼 beeke 2011-01-05  
这个,POEAA讲得很清楚了
2 楼 KimHo 2011-01-05  
有些文字总觉得在哪看过……孙伟琴?
orm映射是个过渡时期的产物,随着OODB的推广和不断成熟,orm映射将慢慢退出历史的舞台。
1 楼 aronlulu 2011-01-05  
标题大,雨点小啊。
两个阻抗失衡的概念有点意思,其实完全按照三范式设计数据库不会那么失衡的,很多情况是中国式业务复杂,完全按照业务来设计数据库,所以失衡严重了,这时候缓存用不起来或者很不好用,命中率太低,性能就变差了。
最好用OODB,或许这才是王道,纵观NOSQL大行其道,其实也是逐渐往这方面靠,数据库OO化,提高内存利用率,不断的螺旋上升。

相关推荐

    Hibernate O/R Mapping 入门工程包

    总结来说,这个"Hibernate O/R Mapping 入门工程包"提供了从XML到Annotation的映射示例,以及简单的数据库操作实例,是学习和理解Hibernate ORM机制的良好起点。通过深入学习和实践,开发者可以更高效地在Java应用中...

    hibernatePPT培训文档

    【hibernatePPT培训文档】是一个针对初学者的Hibernate入门教程,旨在帮助读者理解对象/关系映射...通过学习这个培训文档,开发者将能深入理解O/R Mapping,熟练掌握Hibernate的核心功能,从而在实际项目中游刃有余。

    hibernat培训

    【hibernate培训】课程是针对熟悉Java、SQL和JDBC,掌握面向对象开发方法的开发者,旨在深入理解O/R Mapping原理,掌握Hibernate框架,并能够实际运用到项目开发中。本课程涵盖了以下主要内容: 一、持久化层—O/R ...

    SQL2JAVA

    《SQL2JAVA:深入理解O/R Mapping工具》 在当今的软件开发中,尤其是在企业级应用领域,数据库管理和数据操作是至关重要的环节。SQL2JAVA作为一个O/R Mapping(对象关系映射)工具,旨在简化数据库与Java应用程序...

    hibernate培训教程

    本教程旨在帮助学员深入理解O/R Mapping原理,专注于流行的Java持久化框架Hibernate。学习此教程前,建议学员具备Java、SQL、JDBC的基础知识,以及面向对象开发的经验。通过培训,学员应能了解Hibernate的架构,掌握...

    马士兵hibernate学习笔记(原版)

    通过这份笔记的学习,读者不仅可以掌握Hibernate的基本用法,还能深入理解O/R Mapping的概念和优势,为开发高效、跨平台的Java应用奠定坚实基础。同时,笔记中提供的资源链接和FAQ解答可以帮助解决实际操作中遇到的...

    hibernat培训.ppt

    本培训材料主要针对Hibernate这一流行的Java对象关系映射(ORM)框架,旨在帮助已经熟悉Java、SQL和JDBC的开发者深入理解O/R Mapping原理,掌握Hibernate的使用,以便在实际项目开发中有效地利用Hibernate进行持久化...

    hibernate培训PPT

    总之,Hibernate培训PPT旨在帮助开发者深入理解O/R Mapping的原理,掌握Hibernate框架的使用,以提升Java应用程序的开发效率和数据库操作的便利性。通过学习,开发者将能够有效地将复杂的对象模型映射到关系数据库,...

    Attribute 学习

    在“AttributeStudy”这个压缩包中,可能包含了一系列教程、示例代码或者练习,帮助你深入理解和实践Attribute O/R Mapping。你可以通过阅读文档、运行代码实例、尝试不同的映射配置以及解决可能出现的问题来提升这...

    HIBERNATE入门

    培训目标是使学员理解O/R Mapping原理,熟悉Hibernate架构,掌握对象和关系的映射方法,并能在实际项目中运用Hibernate。 【标签】"hibernate j2ee"表明本教程内容与Java企业级应用(J2EE)开发有关,Hibernate是...

    HIbernate 教程 资料 培训 学习

    【Hibernate 教程 资料 培训 学习】 Hibernate 是一款强大的Java对象关系映射(ORM)框架...通过深入理解O/R Mapping原理,熟练运用Hibernate的特性,可以更好地应对复杂的数据库操作需求,为项目开发带来显著的便利。

    hibernat培训.ppt[评价可免费]

    《Hibernate培训》是针对Java开发者的教程,旨在深入理解对象关系映射(O/R Mapping)原理,特别是通过Hibernate框架实现这一映射。本教程适合熟悉Java、SQL和JDBC,有面向对象开发经验的学员。课程的目标是使学员...

    hibernate学习幻灯片

    【hibernate学习幻灯片】的讲解涵盖了多个关于Hibernate框架和对象/关系映射(O/R Mapping)的核心概念。...深入理解Hibernate的映射机制、对象状态管理、查询方式及最佳实践,是提升Java应用开发效率和质量的关键。

    hibernat培训教程,基础教程

    总结来说,Hibernate教程的目标是让学习者理解O/R Mapping原理,掌握使用Hibernate进行项目开发的技能,通过实践应用提升开发效率和代码质量。通过深入学习和实践,开发者可以更高效地管理和操作数据库,减少与底层...

    hibernate2ch_reference.pdf

    这份详尽的Hibernate文档"hibernate2ch_reference.pdf"将带你深入理解Hibernate的核心概念和最佳实践,无论你是初学者还是经验丰富的开发者,都能从中受益匪浅,进一步提升你在Java ORM领域的专业能力。

    Hibernate学习笔记(很详细哦)

    由于JDBC操作数据库繁琐且SQL语句非面向对象,O/R Mapping提供了一种机制,使我们能够直接使用对象来操作数据库,从而大大简化了代码的复杂度,增强了代码的可读性和可维护性。此外,O/R Mapping还具有跨数据库平台...

Global site tag (gtag.js) - Google Analytics