|
知识路径: > 数据库主流应用技术 > 数据库主流应用技术 > 数据库主流应用技术 > 面向对象数据库 >
|
被考次数:7次
被考频率:中频率
总体答错率:60%  
知识难度系数:
|
由 软考在线 用户真实做题大数据统计生成
|
相关知识点:8个
|
|
|
|
在今天的商业领域中,有许多可用的数据库管理系统产品,占统治地位的主要有两个:关系数据库系统和面向对象数据库系统,分别支持关系数据模型和对象数据模型。数据库管理系统产品的另外两种主要类型是:层次数据库和网状数据库,它们分别基于层次和网状数据模型。随着数据库技术的发展,后两种数据库系统会逐渐被前两种所取代。
|
|
|
数据库系统面临着许多领域的新的应用挑战,如音频和视频处理系统中的数字化信息,计算机辅助桌面排版系统中的大文本,人造卫星成像或天气预报中的图像,工程设计、生物基因组信息、建筑图中的复杂数据,股票市场交易历史或卖出历史中的时间序列数据,地图数据和业务数据中的空间和地理数据。显然需要设计某些数据库,它们可以开发、操纵和维护来自这些应用的复杂对象。
|
|
|
在面对上述复杂应用时,基本关系模型及其SQL语言的早期版本被证明是不适用的。层次数据模型可以很好地适用于在组织中自然存在的分层结构,但是它在数据中的内置层次路径上过于局限和固定。网状数据模型可以明确地对联系建模,但是在实现方面却需要使用大量的指针,而且不具备对象标识、继承、封装这类概念,也不支持多种数据类型和复杂对象。因此产生了一种趋势,即将对象数据模型中的特征和语言结合到关系数据模型中,这样扩展了关系数据模型,形成了对象关系数据库系统,使它能够处理当今复杂的应用。
|
|
|
对象关系数据模型扩展关系数据模型的方式是通过提供一个包括复杂数据类型和面向对象的更丰富的类型系统。关系查询语言也需要做相应地扩展以处理这些更丰富的类型系统。对象关系数据库系统以对象关系数据模型为基础,它为想要使用面向对象特征的关系数据库用户提供了一个方便的迁移途径。
|
|
|
|
在关系数据理论中定义了第一范式,它要求所有的属性都具有原子的域。原子域是指这个域中的元素是不可再分的单元。然而并非所有的应用都是用第一范式关系建模最好。例如,某些应用的用户将数据库视为对象的一个集合,而不是记录的一个集合,这些对象可能需要数条记录来表示。一个简单、易用的界面要求用户直观概念上的一个对象与数据库系统概念上的一个数据项之间是一一对应的关系。
|
|
|
嵌套关系模型是关系模型的一个扩展,域可以是原子的也可以赋值为关系。这样元组在一个属性上的取值可以是一个关系,于是关系可以存储在关系中,从而形成了关系的嵌套。这样一个复杂对象就可以用嵌套关系的单个元组来表示。如果我们将嵌套关系的一个元组视为一个数据项,在数据项和用户数据库观念上的对象之间我们就有了一一对应的关系。
|
|
|
|
嵌套关系只是对基本关系模型扩展的一个实例,其他非原子数据类型,如嵌套记录,同样已被证明是有用的。面向对象数据模型已经导致了对于如对象的继承、引用等特征的需求。有了复杂对象系统和面向对象,我们能够直接表达E-R模型的一些概念,如实体标识、多值属性、一般化和特殊化,而不再需要经过关系模型的复杂转化。
|
|
|
通过对SQL的扩展,我们可以使用复杂类型。下面关于复杂类型的一些简单概念加以介绍。
|
|
|
|
|
这个表中的keyword属性比较特殊,因为它允许属性是集合。
|
|
|
集合是集合体类型的一个实例,其他的集合体类型包括数组和多重集合。因此不同于普通关系数据库中表的定义,允许属性是集合,从而E-R图中的多值属性能够直接表述。
|
|
|
现在许多的数据库应用需要存储的属性很大,如一个人的照片,或者更大的,如高分辨率的医学图像或者录像剪辑。在SQL:1999中提供了新字符型数据大对象数据类型和二进制数据大对象数据类型。大对象一般用于外部的应用,通过SQL对它们进行全体检索是毫无意义的。取而代之,应用程序一般只检索大对象的定位器,然后用定位器从宿主语言中操作该对象。
|
|
|
|
|
第一个语句定义了一个类型MyString,它是一个变长的字符串。第二个语句定义了一个类型MyDate,它有三个组成部分:date、month和year。第三个语句定义了一个类型Document,它包含一个name、一个作者的集合author-list、一个类型为MyDate的日期以及一个关键词集合。最后创建表doc,它包含了类型为Document的元组。上述表的定义与普通关系数据库中的表定义是有区别的,因为前者允许属性为集合或者如MyDate那样的属性具有结构类型,这些特征使得E-R图中的复合属性及多值属性能够直接表达。
|
|
|
|
在这里的介绍是基于SQL:1999标准的,不过也会提到一些在这个标准中没有出现的,但是在SQL标准的未来版本中会介绍到的一些特征。
|
|
|
继承可以在类型的级别上进行,也可以在表的级别上进行。首先考虑类型的继承。
|
|
|
|
|
如果要在数据库中对那些是学生或教师的人分别存储一些额外的信息,由于学生和教师都是人,因而可以使用类型继承来定义学生和教师类型如下:
|
|
|
|
Student和Teacher都继承了Person的属性,即name和address。Student和Teacher都被称为Person的子类型,Person是Student的父类型,同时也是Teacher的父类型。
|
|
|
现在假定要存储关于助教的信息,这些助教既是学生又是教师,甚至可能是在不同的系里。如果类型系统支持多重继承,可以为助教定义一个类型如下:
|
|
|
|
TeacherAssistant将继承Student和Teacher的所有属性,但是却有一个问题,因为name、address和department同时存在于Student和Teacher中。
|
|
|
name和address属性实际上是从同一个来源即Person继承来的,因此同时从Student和Teacher中都继承这两个属性不会引起冲突。然而department属性在Student和Teacher中分别都有定义,事实上,一个助教可能是某个系的学生同时又是另一个系的教师。为了避免两次出现的department之间的冲突,可以使用as子句将它们重新命名,如对TeacherAssistant类型定义如下:
|
|
|
|
在SQL:1999中只支持单继承,即一个类型只能继承一种类型,使用的语法如同前面提到的例子。TeacherAssistant例子中的多重继承在SQL:1999中是不支持的。
|
|
|
|
|
|
那么再定义表students和teachers作为people的子表,如下:
|
|
|
|
子表的类型必须是父表类型的子类型,因此people中的每一个属性均出现在子表中。
|
|
|
当我们声明students和teachers作为people的子表时,每一个students和teachers中出现的元组也隐式存在于people中。所以,如果一个查询用到people表,它将查找的不仅仅是直接插入到这个表中的元组,而且还包含插入到它的子表students和teachers中的元组。然而,只有出现在people中的属性才可以被访问。
|
|
|
面向对象的程序设计语言提供了应用对象的能力,类型的一个属性可以是对一个指定类型的对象的引用。我们可以定义一个Department类型,它有一个name字段和一个引用到Person类型的head字段,然后定义一个Department类型的表departments,如下所示:
|
|
|
|
在上面的定义中,使用关键词scope来限定了引用范围。这里,引用限制在people表中的元组。
|
|
|
|
这里要介绍的是处理复杂类型的扩展SQL查询语言。与复杂类型有关的查询可以分为如下几类。
|
|
|
|
在SQL:1999中对引用取内容使用→符号。可以使用下面的查询来找出各个部门负责人的名字和地址:
|
|
|
|
在上面的查询中,带有→符号的表达式被称为路径表达式。
|
|
|
|
如果我们想找出所有的码中包含“database”字样的书,如下查询即可:
|
|
|
|
unnest(keyword-set)在无嵌套关系的SQL中相当于一个select-from-where的子表达式。
|
|
|
|
将一个嵌套关系转换成为1NF的过程称为解除嵌套。关系doc有author-list和keyword-list两个属性,这两者都是嵌套关系,同时关系doc另外还有name和date两个属性,它们都不是嵌套关系。假定想要将该关系转化为单个平面关系,使其不包含嵌套关系或者结构类型作为属性,可以使用以下查询来完成这个任务:
|
|
|
|
from子句中的变量B被声明以doc为取值范围,变量A被声明以该文档的author-list中的作者为取值范围,同时K被声明以该文档的keyword-list的关键词为取值范围。
|
|
|
反向过程即将一个1NF关系转化为嵌套关系,称为嵌套。嵌套可以用对SQL分组的一个扩展来完成。在SQL分组的常规使用中,需要对每个组创建一个临时的多重集合关系,然后在这个临时关系上应用一个聚集函数。如果不应用聚集函数而只返回这个多重集合,我们就可以创建一个嵌套关系。假定有一个1NF关系flat-doc,下面的查询在属性keyword上对关系进行了嵌套:
|
|
|
|
|
在对象关系数据库系统中允许用户定义函数与过程,它们既可以用某种数据操纵语言如SQL来定义,也可以通过外部的程序设计语言来定义,例如Java、C或C++。有些数据库管理系统支持它们自己的过程语言,如Oracle中的PL/SQL和Microsoft SQL Server中的Transact SQL,它们类似于SQL的有关过程的部分,但在语法和语义上有所区别,详细信息可参见各自的系统手册。
|
|
|
假设定义这样一个函数:给定一个文档,返回其作者的人数。可以定义这个函数如下:
|
|
|
|
这里Document是一个类型名。这个函数用单个文档对象来调用,select语句同关系one-doc一起执行,这个关系仅包括单个元组,即函数的参数。这个select语句的结果是单个值,严格来讲,它是一个只有单个属性的元组,其类型被转化为一个值。
|
|
|
上面的函数可以使用在如下查询中,该查询返回具有多于一个作者的所有文档的名称:
|
|
|
|
注意,上面的SQL表达式中,尽管在from子句中doc是指一个关系,但在where子句中它隐含地被视为一个元组变量,因此它可以用来作为author-count函数的一个参数。
|
|
|
有些数据库系统允许我们使用如C或C++这样的程序设计语言来定义函数。用这种方式定义的函数比用SQL定义的函数效率更高,并且能够执行有些无法用SQL完成的计算。使用这些函数的例子有很多,如在一个元组的数据上做一个复杂的算法。
|
|
|
用程序设计语言定义的函数在数据库系统的外部编译,它们需要被装入并与数据库系统代码一起执行。这个过程要冒一定的风险,因为程序中的错误可能会破坏数据库的内部结构,并且可能绕道数据库系统的存取控制功能。
|
|
|
使用程序设计语言定义的函数看起来与使用嵌入式SQL没什么不一样,使用嵌入式SQL时数据库查询包含在一个通用程序中,但是它们之间还是有一个重要差别。在嵌入式SQL中,用户程序将查询传送给数据库系统执行,结果以一次一个元组的形式返回给该程序。因此,用户书写的代码永远不会需要访问数据库本身,于是操作系统就可以保护数据库不被任何用户进程所存取。当在查询中使用用户编码的函数时,要么这些代码必须由数据库系统本身运行,要么该函数所操作的数据必须被拷贝到一个分离的数据空间中。第二种方法增加了系统开销,第一种方法则诱发了潜在的脆弱性,这同时表现在完整性方面和安全性方面。
|
|
|
|
我们已经研究了建立在持久化程序设计语言上的面向对象数据库,也研究了建立在关系模型之上的面向对象的对象关系数据库。这两种类型的数据库系统在市场上都存在,数据库设计者要选择那种适合应用需求的系统。
|
|
|
程序设计语言的持久化扩展和对象关系系统有着不同的市场目标。SQL语言的声明性特征和有限的能力为防止程序设计错误对数据造成破坏提供了很好的保护,同时使得一些高级优化,例如减少I/O,变得相对简单。对象关系系统的目标在于通过使用复杂数据类型来简化数据建模和查询,典型的应用有复杂数据的存储和查询等。
|
|
|
然而,对于某些类型的应用,如主要在内存中运行和对数据库进行大批量访问的应用来说,一个说明性语言,如SQL会带来显著的性能损失。满足应用的高性能要求就是持久化程序设计语言的目标。持久化程序设计语言提供了对持久数据的低开销存取,并且取消了数据转换的要求。但是,持久化程序设计语言对由于程序错误而引起的数据破坏更为敏感,而且通常没有强大的查询能力。它们典型的应用包括CAD数据库。
|
|
|
|
.关系系统:简单数据类型、功能强大的查询语言、高保护性。
|
|
|
.以持久化程序设计语言为基础的面向对象系统:复杂数据类型、与程序设计语言集成、高性能。
|
|
|
.对象关系系统:复杂数据类型、功能强大的查询语言、高保护性。
|
|
|
这些描述具有普遍性,但是请记住对有些数据库系统来说它们的分界线是模糊的。例如,有些以持久化程序设计语言为基础的面向对象数据库系统是在一个关系数据库系统之上实现的,这些系统的性能可能比不上那些直接建立在存储系统之上的面向对象数据库系统,但这些系统却提供了关系系统所具有的较强的保护能力。
|
|
|