技术开发 频道

实体继承

  【IT168 技术文章】

         面向对象和关系型数据库

  Java 语言天生就是一门面向对象的编程语言,在 Java 世界中,被处理的内容都被组织成一个一个的对象,对象和对象之间存在着继承、引用关系,这样的关系无法通过简单的方式直接映射到关系型数据库中。因此在关系型数据库与面向对象之间存在着阻抗失谐。

  我们通过一个简单的例子来说明这种阻抗失谐给企业应用开发者带来的困难。假设在企业应用中存在三个 Java 类:Animal、Fish 和 Dog。Animal 仅仅具备两个属性:id 和 name。Fish 是一种 Animal,但是人们比较关注它的生活区域是在海里还是在河里,因此它除了继承自 Animal 之外,还有自己独特的属性 territory。Dog 也是一种 Animal,人们比较关注它的性别,因此它除了继承自 Animal 之外,还有自己独特的属性 sex。我们可以用下面这个图描述三者之间的关系模型。

  图 1. Animal、Fish 和 Dog 对象模型

  在 Java 应用中,由于动态绑定的支持,Fish、Dog 都可以被作为 Animal 对象处理。但是如果我们换到关系型数据库的视角,情况发生了改变: 通常情况下,Animal、Fish、Dog 毫无关联,它们都保存在各自对应的表中,假设分别对应 Animal 表、Fish 表和 Dog 表,如果要维护 Animal 和 Fish 的继承关系,我们就需要使用 SQL 的联合查询语句查出 Animal 的所有属性和 Fish 的所有属性,这样就必须使用某种外键进行关联:

1 Select animal.*,fish.* form animal,fish where animal.id = fish.id

  从这个简单的例子中我们就可以看出,一个企业应用开发者使用 Java 实现企业应用时需要同时掌握面向对象和关系型数据库的两种思想,而且还必须保证它们之间的映射是正确的,否则无法保证企业应用的正确性,这对于企业应用开发者是个的挑战,因此 Java 社区一直在寻求如何将面向对象和关系型数据库思想统一起来的简单途径,这方面的努力促进了持久化技术的发展。

  OpenJPA 是最新的尝试,它能够将对象继承关系的持久化透明化,企业应用开发者仅需要处理对象模型,而不需要处理和关系型数据库有关的内容,极大地降低了对象继承关系持久化的难度。下面我们来了解 OpenJPA 中持久化对象继承关系的几种方式。

  持久化对象继承关系的方式

  我们从关系数据库角度看对象继承关系的持久化这个问题域:对象继承通常意味着子类比父类提供更多的属性,持久化对象继承关系的实质就是如何根据对象的类型动态的处理这些多出来的属性。OpenJPA 框架支持使用三种不同的策略处理对象继承关系:

  1. 类及其子类保存在一张数据库表中

  在这种情况下,类及其子类都保存在同一张数据表中,该表提供足够的字段保存类及其子类的所有属性,同时提供一个特别字段保存当前记录对应类的实际类名(默认名 DTYPE,也可以在开发时指定其它名称)。在企业应用运行过程中,OpenJPA 框架根据 Java 对象的实际类型和数据库表进行绑定。

  以上一章节中提到的对象模型为例: Animal、Fish、Dog 三个类的所有对象实例都被保存在 Animal 数据表中,该表将会有 5 个属性,其中 ID,NAME 字段对应 ANIMAL 类的两个属性,ID、NAME、SEX 对应 Dog 类的属性,ID、NAME、STERRITORY 对应 Fish 类的属性。DTYPE 是 OpenJPA 加入的字段,用于确定当前记录的实际类类型,在这里例子中,它的内容是“ANIMAL”、“FISH”或者是“DOG”。

  图 2. 第一种策略的数据库表现

  2. 类和子类分别保存在不同的数据库表中,互相之间没有关联

  这种情况下,开发者不理会类之间是否存在继承关系,为每一个类的持久化使用唯一的表,父类对象保存在父类对应的表中,子类对象的信息保存在子类对应的表中,这也是通常的持久化框架采用的方式。下面这个图显示了这种情况下对象继承关系数据库中的表现。

  以上一章节中提到的对象模型为例: Animal、Fish、Dog 三个类的对象实例都被保存在各自对应的数据表中。下面这个图显示了这种情况下对象继承关系数据库中的表现。

  图 3. 第二种策略的数据库表现

  3. 类和子类分别保存在不同的数据库表中,子类中不保存父类中已有的属性,仅通过主键进行关联

  这种情况下,父类和子类对应不同的表,但是子类对应的表中不再保存父类对应表中已经存在的字段信息,两个表之间通过关键字段关联起来,也就是数据库技术中通常所说的外健。这种实现方式是最理想化的一种,既能够处理对象之间的继承,又满足了关系数据库中对于设计范式的要求。

  以上一章节中提到的对象模型为例: Animal、Fish、Dog 三个类的对象实例都被在 Animal 表中有记录;而 Fish 对象的 TERRITORY 属性者被 FISH 表所保存,FISH 表通过 ID 和 Animal 表中的数据进行关联;而 Dog 对象的 SEX 属性者被 Dog 表所保存,Dog 表通过 ID 和 Animal 表中的数据进行关联。下面这个图显示了这种情况下对象继承关系数据库中的表现。

  图 4. 第三种策略的数据库表现

  这三种方式的处理对于开发者而言是透明的,无论选择哪一种,仅仅影响数据在关系数据库中的保存方式,对于开发者而言,只需要按照面向对象的方式操作对象既可,OpenJPA 框架在处理持久化操作的时候,会动态地判断当前对象的实际类类型(后期绑定),从而确定持久化到哪个表中。在一个企业应用的实现中,开发者可以根据需要选择这三种方式的一种或者几种来处理对象之间的继承关系。

0
相关文章