版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第5章对象及对象—关系数据库理论5.1面向对象的数据模型5.2面向对象的语言5.3持久化程序设计语言5.4对象—关系模型5.5与复杂类型有关的查询5.6函数和过程5.7面向对象及对象—关系数据库应用习题对象数据库技术是面向对象方法与数据库技术结合的产物,是在新型数据应用驱动下产生并发展起来的。在面向对象方法与数据库技术相结合的过程中,出现了两种不同的结合方式。一种方式是基于面向对象数据模型(OODM,ObjectOrientedDataModel)对数据对象的行为和联系进行构建,这样形成的数据库称为面向对象数据库(OODB,ObjectOrientedDataBase)。面向对象数据模型克服了关系数据模型平面化的结构特点,可以表达复杂的数据类型及其上的操作,广泛地应用在新型的数据应用领域,如计算机辅助设计系统、多媒体数据库等等。另一种方式是在关系数据模型的基础上增加面向对象的特性,提供复杂的数据类型和引用数据类型,并扩充SQL语言使之可以操作和控制复杂的对象,这样形成的数据库称为对象—关系数据库(ORDB,Object-RelationalDatabase)。对象—关系模型既兼容传统的关系数据模型,具有良好的通用性,又具备了面向对象的特征,是关系数据模型转向面向对象数据模型的中间形式。本章首先介绍面向对象的数据模型以及持久化程序设计语言,然后再介绍对象—关系模型及其上的查询和操作,最后以一个对象—关系数据库的应用实例作为示例,并对这两种数据库进行对比。5.1面向对象的数据模型传统的数据库应用大多采用实体—关联图进行数据建模,在此基础上设计关系数据模型,再根据此模型建立数据库管理系统。由于关系数据库的操作对象是关系表结构,因此决定了基于关系数据库的应用大都具备以下特征。
(1)数据及结构的一致性:具有相似的结构化数据和相同的大小。
(2)面向记录:基本数据由定长的数据组成。
(3)数据项较小:每条记录不超过几百字节长。
(4)字段的原子性:记录字段较短,不可再分,满足1NF。然而,在新型的数据应用中,尤其是需要寻找处理复杂数据类型的应用中,传统的关系数据模型已无法满足复杂数据处理的需求。例如:
(1)计算机辅助设计(CAD)中,储存工程设计的数据,包括被设计的构件、构件间的联系、设计的版本等。
(2)计算机辅助软件工程(CASE)中, 存储和管理软件开发人员使用的数据,包括源代码、软件模块间的依赖关系、变量的定义与使用、软件系统的发展历史等。
(3)多媒体数据库中,多媒体数据包括图像、空间数据、音频数据、视频数据等,主要应用在地理信息系统(GIS)、语音邮件系统、图形系统、音频点播(AOD,Audio-On-Demand)、视频点播(VOD)等。
(4)超文本数据库。超文本由文本和指向其他文档的钩链构成。WWW系统是一个超文本的例子,确切地说,它是一个超媒体的例子,因为Web文档可能是多媒体文档。超文本数据库必须支持基于钩链的文档检索和基于结构的文档查询功能。以上这些应用采用关系数据模型建模就比较繁琐,甚至引起昂贵的开销。而数据模型是对现实世界中实体本身及其约束的抽象描述和实体间相互联系的逻辑刻画,以面向对象方法为指导对数据模型进行定义和解释,就可以构建面向对象数据模型。基于OODM描述现实世界中的实体(对象)的逻辑结构和对象之间的联系与限制是构建面向对象数据库的基础。5.1.1对象结构对象(Object)是客观世界中实体的抽象表示,如学生、飞机、报表等等。对象概念需要做进一步描述才能使其具体化与技术化,对象结构就是这种具体化与技术化的描述。通常,对象由一组数据结构以及其上的一组方法(代码)封装为一个对外不可见的基本单位,主要包含以下内容。
(1)变量(Variable)集合:存放对象的属性数据。
(2)消息(Message)集合:对象与系统进行交互的接口。
(3)方法(Method)集合:实现消息的代码段,返回值为对消息的响应。由变量集合、方法集合和消息集合3部分加上对象标识构成的对象封装体称为对象结构。下面分别对变量、消息和方法进行详细介绍。
1.变量任何一个对象及属性都有一种类型。对象系统的类型由一组系统自身定义的基本类型和类型构造器构造的复杂的结构类型构成。基本类型包括基础类型和“类”类型。通常意义上的整型、字符串型和布尔型等数据类型都是基础类型,而“类”类型将“类”作为一个整体看成一个基础的型,可以像基础类型一样对待和使用(关于类的详细说明见5.1.2节)。结构类型可以通过类型构造器对基础类型和“类”类型进行构造。在对象系统中,类型构造器有数组(Array)、链表(List)、集合(Set)、多重集合(Bag)、记录(Record)等。需要指出的是,基础型对象的值是“自我定义”的,而结构型对象的值是由其部件对象的对象标识(详见5.1.5节)的相应组合确定的。
2.消息对象中的“消息”与计算机网络中传输的消息的概念不同,它是指对象之间的联系信息,是操作请求的传递,并不考虑操作实现细节。消息是实现对象功能的主要手段,通过相互发送消息来激发动作。对某对象进行一次方法调用,称为向该对象发送一个消息。发送一个消息要考虑3方面内容:接收的对象、使用的方法和所需参数(可以有0个、1个或多个)。一个对象可以接受不同形式与内容的多个消息,同时,相同形式的消息也可以发往不同的对象。不同对象对形式相同的消息可以有不同的解释,完成不同的操作。
3.方法方法是施加到对象的操作,对象的操作通过调用其自身包含的方法来实现。由于方法与对象和类封装在一起,因而比传统数据模型上的操作语义更强。例如,一个定义“圆形”的类,除了可以对它进行查询和修改外,还可以通过方法实现图形的放大/缩小、移动拼接等操作。此外,方法与消息还可以表示数据模式约束,称为完整性约束方法与完整性约束消息,通常带有特殊标识。一个对象的方法可以分为只读与更新,只读方法不影响对象中的变量的值,反之,更新方法则可能改变变量的值。类似地,对象所响应的消息也可以根据实现这些消息的方法分成只读与更新。5.1.2对象类类(Class)是对具有共用属性和方法的相似对象的抽象描述,它相当于关系模型中的关系模式。类中的所有对象共享一个公共的定义,每一个对象称为类的一个实例(Instance),不同对象的变量值可以不同。类概括了一些对象的共有性质、方法和数据,简化了人们对客观世界中复杂对象的认识,从而避免了对相似对象的重复定义。如果将类本身看做一个对象,则一个类对象包括:
(1)一个由该类所有实例对象组成的变量集合;
(2)在类之间进行通信的消息集合;
(3)实现消息的方法集合。类除了具有对象的特征外,还有一些附加特性,如生成实例对象的方法new。在本质上,面向对象方法中研究对象的基本抽象单位是类而非对象。
例5.1
用伪代码定义类“雇员”。
CLASSemployee{
//变量
SHORTID;
STRINGname;
DATEbirthDate;
DATEhireDate;
ADDRESS
home_address;
SET<Phone_no>phones;
//消息
INTsalary();
STRINGget-name();
INT
set-name(STRINGnew-name);
ADDRESSget-address();
INTset-address(ADDRESSnew-address);
INTemployment-length();}每个employee对象都包含字符串型变量name、短整型变量ID、日期型变量birthDate和hireDate。这些变量类型为系统自身定义的基本类型,ADDRESS型变量home_address和SET<Phone_no>型变量phones是结构类型,前者将地址信息封装为一个名为ADDRESS的类,后者使用一个电话号码集合来记录多个电话号码。每个employee对象都响应对应的消息,消息前面的类型名表示对消息的响应类型。其中,消息set-name接受一个参数new-name来指定名字的值。通常,消息处理方法的定义与类定义是分开的,例如,方法set-name()的定义如下:
INTset-name(STRINGnew-name){
name=new-name;}类似地,employee类也应该提供用来读取和设置工号、薪水、工作日期等的消息,在此没有一一指明。5.1.3继承类与类之间的基本关系有3种:继承关系、包含关系和通信关系(消息)。其中,继承关系和包含关系反映了类与类之间的静态联系,是基本的类关系;通信关系反映的是类与类之间的动态联系,通过消息实现。本节就介绍类与类之间的基本层次结构——继承(Inheritance)。继承是一个类能够自动继承其他类所具有的属性和方法的机制。由现有类导出新的类,这个新的类不但可以继承原类的全部属性和方法,而且还可以定义它自己额外的属性和方法,以及重定义继承的方法。新类称为原类的“子类”(Subclass),是类的特化,原类称为导出类的“超类”(Superclass),是类的泛化。继承实现了实体—关系概念建模中的“IS-A”联系。一个子类可以有一个或多个超类,一个超类也可以有一个或多个子类,具有继承关系的类形成了类与类之间基本的层次结构。图5.1显示了超市例子中人员之间的继承关系。其中,雇员和顾客是人的子类,店长和店员是雇员的子类,相应地,人是雇员和顾客的超类,雇员是店长和店员的超类。图5.1超市例子中人员之间的继承关系在面向对象系统中,类的继承具有以下几个基本性质:
(1)传递性(Transitivity)。假设有A、B、C三个类,其中C继承B,B继承A,那么C也继承A。继承的传递性使得面向对象系统可以反映客观世界中多层次关系,例如在图5.1中,雇员是店长和店员的直接超类,人又是雇员和顾客的直接超类,这样,无论是雇员还是顾客,是店长还是店员,都继承了人类的特征。
(2)单向性(Unidirectionality)。假设B类继承A类,那么A类一定不能再继承B类。继承的这种性质避免了在面向对象系统中无限递归的情况。单向性与传递性共同决定了继承的单向层次性。
(3)可置换性(Substitutability)。即一个超类的方法可以被其子类的任何对象调用。根据传递性,子类可以调用继承层次上的所有超类资源。这样可以避免大量的对消息、方法和函数的重写。
(4)多态性(Polymorphism)。即超类的属性与方法在子类中允许有不同的实现形式、方法与语义。继承的多态性对类的特征和行为进行了有效的扩充。类的多态性允许子类提炼(Refine)和重载(Overload)来自超类的属性与方法。其中,通过对超类继承过来的方法进行修正而得到子类的方法称为提炼,例如圆锥体的体积可通过对圆柱体的体积计算进行提炼(修正)而得到;而在子类中以新的内容重新定义超类中已有的属性和方法称为重载,例如在图形类中定义一个打印方法用于打印图形,对图形类中的不同实例,打印的过程可以不同。5.1.4多重继承当一个类只有一个超类时,称这种继承为单一继承;当一个类有多个超类时,称这种继承为多重继承。多重继承可以通过组合几个类的描述到一个类而提高共享能力,通常用一个有向无环图(DAG,DirectedAcyclicGraph)来表示。例如,超市中的雇员既可以是临时的,也可以是固定的。在类的表述上,对临时员工,可以用属性term-date来指定雇佣期限的终止;而对于固定员工,可能含有一个用于计算养老金的方法,而这个方法对临时员工是不适用的。这种根据工作时间对雇员的划分方式与根据工作职责进行划分的方式是相互独立的,通过多重继承,可以简单地创建新类,如临时店员和固定店员。图5.2显示了多重继承的类层次结构。通过多重继承,临时员工和固定员工的特定属性和方法可以只说明一次而被所有的子类继承。图5.2超市例子的DAG但是,当同一个变量或方法从多个超类中继承时会有潜在的二义性问题。考虑另外一个例子,一所大学中的助教既可以由教师来担任也可以由学生来担任。在类层次的定义上,助教类继承了教师类和学生类两个类的特征。假设教师类和学生类都定义了属性“部门”,那么助教类中继承的“部门”属性就可能对应两个值,即存在二义性。例如,计算机系的学生同时担任自动化系的助教,那么助教的“部门”属性值就有两种选择。在不同的系统中,解决由多重继承引发的二义性冲突的方法也有所不同。通常有以下几种解决方式:
(1)重新命名。将部门属性分为两个变量,分别命名为“部门_学生”和“部门_教师”。
(2)系统根据学生类和教师类的创建顺序选择其中一个作为助教的部门属性。
(3)用户根据自身的需要选择助教的部门属性值。
(4)系统作为错误进行处理,这种系统可能不允许多重继承。当然,并不是所有的多重继承都会导致二义性。在超市例子中,临时员工、固定员工、店长和店员都从雇员中继承属性变量“薪资”,由于所有类都共享一个“薪资”定义,因而临时店员和固定店员中的变量继承就不会出现二义性。5.1.5对象标识在面向对象数据库中,一个对象通常对应着现实世界中的一个实体。一个实体可以有一个或多个有意义的名字,相应地,由实体的应用产生的名字就可以作为对象名字。但是,实体名字可能随着时间的推移发生改变,不同的实体也可能拥有相同的名字,这样就为定位和操作数据库中的对象带来了困扰。因此,面向对象系统使用对象标识符(OID,ObjectIdentifier)来标识对象。例如,对象标识符可以是一长串的数字,由对象在数据库中的存储位置和一些其他的信息构成。对象标识通常是由系统产生的,而对象名字是由应用产生的。在面向对象系统中,对象名字在整个数据库范围中必须唯一,一个对象可以具有多个名字,但一个名字只能表示一个对象,类似于编程语言中的全局变量。而对象标识符是对象的身份表示,与对象名字相比,对象标识符具有以下特征:
(1)唯一性:OID在对象的整个生命周期内是保持不变的。
(2)不可重用性:一旦某个对象被删除之后,该对象的OID不可重用。
(3)独立于对象状态:不随对象变量状态的变化而变化。
(4)独立于对象的物理存储位置:当对象的存储位置发生变化时,OID应保持不变。相对于程序设计语言或非面向对象数据模型中通常使用的标识来说,对象标识符是一种更强的标识概念。例如,在文件系统中,用名称作为标识文件的手段,在关系数据库系统中,用值作为标识数据的手段,即关键字。表5.1列出了关系数据库系统中关键字与面向对象系统中对象标识符之间的对照关系。表5.1关键字与对象标识的对照5.1.6对象包含对象包含是对象之间静态联系的一种关系,通过对象之间的引用可以对现实世界中不同的概念进行建模。例如,一台标准的家用个人计算机包括主机、显示器、音箱和输入设备等构件,输入设备包括鼠标和键盘,主机又包括主板、CPU、显卡和内存。这其中的每一个构件既可以单独出售,也可以组装在一起出售,可以将每个构件建模为一个对象,那么构件间的包含就可以建模为对象间的包含。图5.3中的类层次结构显示了对象间的包含关系,其中,包含其他对象的对象称为复杂对象(ComplexObject)或复合对象(CompositeObject),对象之间可以存在多层次的包含。图5.3台式机的包含层次类之间的包含关系实现了概念建模中的“IS-PART-OF”联系,它允许不同的用户用不同的粒度来观察数据。例如芯片制造商可以专注于CPU的研发和销售,而不必过多考虑(或无需考虑)键盘、鼠标等输入设备;而对于台式机销售人员来说,为了给整台电脑定价,可以使用包含层次来寻找包含在台式机对象中所有对象的价格。当然,一个对象也可能包含在多个对象中,这种包含关系不能用层次来表示。与多重继承类似,可以用一个DAG来表示被多个对象包含的对象。5.2面向对象的语言在技术开发和实际应用中,面向对象的概念要通过某种语言进行必要的表述与刻画,从而可以在数据库系统中使用它们。在数据库设计阶段,面向对象的概念可以通过实体—关联图进行建模,或者通过统一建模语言UML来表达。与E-R模型不同,UML是为了创建软件系统不同部分的规范而提出的对象建模标准,而不仅仅面向数据库系统设计的应用。因此,E-R图更适合于在关系数据库设计时采用,经过手工转化为二元关系后再编码到关系数据库当中去,而UML可以作为面向对象数据库的设计工具对实体对象进行描述和表达。当面向对象的概念与操纵数据库的语言进行结合时,可以有两种方式对语言进行集成:通过增加某种复杂类型和面向对象特征来扩展某种数据操纵语言(如SQL),或者找一种现存的面向对象程序设计语言,将它扩展以便能对数据库进行处理。前者是在关系数据库系统之上提供面向对象扩展,这样的系统被称为对象—关系系统,系统中采用的数据操纵语言为SQL的面向对象的扩展,如SQL2003。后者通常对面向对象程序设计语言如Smalltalk、C++ 和Java等进行扩展,这样的语言被称为持久化程序设计(PersistentProgramming)语言。
20世纪80年代成立的对象数据管理小组(ODMG,ObjectDataManagementGroup)一直致力于对面向对象语言的扩展进行标准化的工作。1993年发布的OODB工业标准ODMG1.0完成了对C++ 的数据库功能的扩充,其主要特征是将对象作为基本构建而不是表。在后续推出的ODMG2.0和ODMG3.0中,将对象模型和对象查询语言从C++扩展到了Smalltalk和Java。
ODMG工业标准对面向对象程序设计语言的扩展主要包括对象定义语言(ODL,ObjectDefinitionLanguage)和对象操纵语言(OML,ObjectManipulateLanguage)。其中,OML又分为对象查询语言(OQL,ObjectQueryLanguage)和对象控制语言(OCL,ObjectControlLanguage)。ODMG工业标准中的对象数据模型主要包括以下5个概念:
(1)对象(Object)和字面量(Literal)。对象和字面量是基本建模的单位。每个对象有一个唯一的标识符,并且在对象的整个生命周期内都有效。而字面量没有标识符。
(2)型(Type)。一个型是一个外部说明和一个或多个实现,外部说明是对象的抽象,包括对象的操作和特征。每个对象和字面量都具有一个型,某个型的所有元素具有相同的状态和行为,而对象可以称为型的实例。其中,型又有3种定义方式:接口、类和字面量。接口型仅定义一个对象型的抽象行为,类型定义一个对象型的抽象行为和抽象状态,字面量型仅定义了一个字面量型的抽象状态。一个型可以有多个实现,如用C++或Java实现。但在一种绑定语言中,一个型通常只有一个实现。ODMG工业标准使型的说明独立于型的实现,更加有利于型的多语言存取和异构计算环境中对象的共享。在接下来的5.3.4节中,将通过例子介绍用C++ 实现的对象系统,在5.3.5节中,主要说明Java实现的对象系统与C++ 系统的不同之处。
(3)状态。一个对象的状态由一组特征来描述,特征包括属性(Attribute)与联系(Relationship)。
(4)操作或方法(Method)。一个对象的行为由一组操作来描述,操作具有输入和输出参数,并且可以返回特定型的结果。5.3持久化程序设计语言数据库存储的数据被看做是持久化数据(PersistentData),即当创建数据的程序终止后数据仍然存在。相应地,在结构上扩充了的可以处理持久数据的程序设计语言被称为持久化程序设计语言。在数据库语言与程序设计语言集成的过程中,传统的方法是在程序设计语言中嵌入SQL,这种嵌入式SQL的语言与持久化的程序设计语言可以从以下两方面进行区分。
1.类型阻抗嵌入式语言与宿主语言存在类型阻抗问题,即宿主语言的类型系统通常与数据操纵语言的类型系统有所不同。这就要求程序设计者负责宿主语言和SQL之间的类型转化,这不但会增加应用程序中类型转换的代码量,也会因此引入潜在的错误。与此相比,持久化编程语言的查询语言已完全集成到宿主语言中,共用相同的类型系统,对象在数据库中的创建和存储可以不需要任何显式的类型或格式转换,任何所需格式转换的实现都是透明的。
2.内存与磁盘之间的数据交换格式嵌入式语言设计者负责编写外在代码以完成把从数据库取出的数据放入内存的操作。如果数据做了更新,程序设计者还要编写代码将更新后的数据写回到数据库中。与此相比,持久化编程语言无需显式编程将数据取到内存或写回到磁盘就可操作持久化数据,更紧密地将程序设计语言与数据库集成在一起。但是,持久化程序设计语言缺少数据库操作语言对数据完整性和一致性的约束,因此很容易会因编程错误而破坏数据库。另外,持久化程序设计语言的复杂性使得自动的髙级优化(例如减少磁盘I/O)比较困难,并且目前的持久化程序设计语言对说明性查询的支持也不理想。因此,持久化程序设计语言也有其不足之处。5.3.1对象的持久化在面向对象数据库中存储的对象数据是持久化对象,为了使面向对象语言可以创建和操作持久化对象,即将这种语言变成数据库程序设计语言,首先要提供一种方法使对象变成持久的,有以下几种方法。
1.类持久化(PersistencebyClass)说明某个类是持久化的,则该类中的所有对象是持久化的,非持久化类的所有对象是挥发性的。该方法比较简单但不够灵活,因为在一个类中既有持久化对象又有挥发性对象对用户来讲总是有用的和方便的。因此在许多面向对象的数据库系统中类为“可持久化”类。
2.建立持久化(PersistencebyCreation)通过重载并扩展创建瞬态对象的语法来建立持久化对象,如new操作。一个对象是否为持久化取决于该对象的建立过程。有些面向对象的数据库系统采用这种方法建立持久化的对象。
3.标记持久化(PersistencebyMarking)标记持久化是建立持久化方法的变种,是在一个对象建立以后将其标记为持久性对象。一般来讲,所有对象是作为挥发性对象来建立的,但是如果该对象的生命周期超过程序的执行期间的话,则它必须在该程序结束前被显式地标记为持久化对象。方法2和方法3的区别是:前者在对象建立前决定是否持久化,而后者是在对象建立后才决定其是否持久化。
4.引用持久化(PersistencebyReachability)如果一个或多个对象被显式地说明为持久化根对象,那么所有直接或间接被这些持久化根对象引用的所有对象均为持久化对象,即持久化对象就是那些从持久化根对象可达到的。这种方案的优点是易于创建持久的数据结构,只需声明数据结构的根为持久的就可以了。然而,这种方式需要沿着引用链查找以便确定对象是否是持久,而这个操作的代价可能是很高的,这就是引用持久化的不足。5.3.2对象标志与指针在面向对象的数据库系统中,既有挥发性对象也有持久化对象。一般来讲,挥发性对象存储在内存中,由程序设计语言运行系统来管理,而持久化对象存储在内存和磁盘中,由面向对象的数据库管理系统来管理。当创建一个挥发性对象时,系统返回的是一个瞬态对象的标识符。瞬态对象标识符只有当创建它的程序正在执行时才是合法的;一旦程序结束,该对象就被删除,同时其标识符也就没有任何意义了。当创建一个持久化对象时,对象被赋予一个持久化对象标识符。标识的持久程度有以下几种:
(1)过程内部持久(Intra-procedure):在过程的执行期间标识是有效的,如过程内的局部变量。
(2)程序内部持久(Intra-program):在程序或查询执行期间标识是有效的,如全局变量。
(3)程序之间持久(Inter-program): 从一个程序执行到另一个程序执行之间标识都是有效的。指向磁盘上文件系统数据的指针提供了程序之间的标识,但是当数据在文件系统中的存储方式发生变化时,它们有可能被改变。
(4)持久的(Persistent):标识不仅在各个程序的执行期间有效,在数据结构的重新组织后仍然有效。这种持久化是面向对象数据库系统中对象数据的特征。对象标识可以通过指向存储空间的物理位置的指针得到,挥发性对象的指针通常就是内存指针,持久化对象的对象标识符用“持久化指针”来实现。与内存指针不同,持久化指针即使在程序结束后仍然是有效的,程序设计者可以像在程序设计语言中使用内存指针一样使用持久化指针。概念上,可以将持久化指针看成指向数据库中某个对象的指针。5.3.3持久化对象的存储与访问在面向对象的数据库中,一个对象的数据部分被单独地存储在数据库中,而实现一个类的方法的代码部分是作为数据库模式部分存储的,包括类的类型定义。但是在许多系统实现中,方法实现的代码存储在数据库外面的文件中,以避免将诸如编译器这样的系统软件集成到数据库系统中来。在数据库中,持久化对象的访问可以通过以下几种方法实现:
(1)通过对象名字:这种方法仅适合于少量对象的查找,即在数据库中不能命名大量对象时,就会降低通过名字查找对象的效率。通常数据库的入口是通过查找名字得到的。
(2)通过对象标识符:对象的标识符可以是对象的持久化指针,因而这种方法是实现导航查找对象的方法。
(3)集合对象的查找:允许程序在一个对象的集合之上进行迭代以找到所需要的对象。通常对象的集合被建模为聚集类型(CollectionType)的对象。聚集类型包括集合、多重集合(即同一个值可能出现多次的集合)、列表等等。
(4)类的外延:类的外延(Extent)是一种特殊的聚集类型,是属于一个类的所有对象的集合。如果一个类存在外延,则在创建该类的一个对象时该对象被自动地插入到类的外延中,删除该类中的对象时,该对象也自动地从外延中删除掉。类的外延的维护使得该类具有关系的性质。多数面向对象数据库系统支持以上几种访问持久化对象的方法。它们将对象标识赋予所有的对象,一般只对类的外延和其他聚集类型对象赋予名字。在很多系统实现中,类的外延只包括类的持久化对象。5.3.4持久化C++ 系统基于C++ 的持久化扩展的面向对象数据库系统简称持久化C++ 系统。C++ 语言的一些面向对象特征有助于为持久化提供很多支持而无需改变语言本身。对象数据库管理组(ODMG)标准通过模板类和类库提供支持持久化所有的功能,而不对C++语言做任何扩展。
ODMG的C++ 扩展包括C++ 对象定义语言(C++ODL)、C++对象操纵语言(C++OML)和ODMGC++ 对象查询语言,其中,C++ ODL扩展了C++的类型定义语法。
1.ODMGC++ 对象定义语言在C++ 对象定义语言中,通过对持久化类d_Object的继承来创建持久化对象。由于C++不直接支持消息的概念,在持久化C++ 系统中用直接调用的方法来实现。例5.2用ODMGC++ 对象定义语言定义连锁超市人员系统。
CLASSChain:publicd_Object{
PUBLIC:
d_Stringchain_name;
d_Shortchain_number;
d_Shortbalance;
d_Stringaddress;
d_Set<d_Ref<Customer>>members;}
CLASSPerson:publicd_Object{
PUBLIC:
d_Stringname;
d_Stringaddress;}
CLASSCustomer:publicPerson{
PUBLIC:
d_Datememberfrom;
d_Longcustomer_id;
d_Shortmembership_point;
d_Ref<Chain>home_chain;
d_Shortget_point();
intalter_point(d_Shortdelta);}其中,每个类都继承自d_Object类,而Person和Chain是d_Object的直接子类,Customer类是Person的子类,间接地继承了d_Object,因而,由这些类创建的对象也是持久的。类型d_String、d_Short、d_Long和d_Date是ODMG定义的标准类型,系统依据不同的类型为持久化对象分配不同的存储空间,因而不能用string、short、long等C++ 语言定义的数据类型替换。Customer类中声明的方法get_point()和alter_point(d_Shortdelta)用于对会员的积分point进行读写。
Customer类中使用的类型d_Ref<Chain>是一个引用,指向类型为Chain的一个对象,而Chain类中定义的d_Set<d_Ref<Customer>>是一个指向Customer类型对象的集合。其中,d_Ref和d_Set是ODMG-2.0标准中的定义的模板类。
Customer和Chain之间的引用表达了Customer和Chain对象之间的参照关系。当Customer对象从它的home_chain属性引用一个Chain对象,必有一个反向引用从Chain对象通过members属性指回Customer对象。 程序员可以在ODMG-2.0中定义参照完整性约束,系统会自动维护它们。模板类d_Rel_Ref<T,A>提供了一个插入一个引用的方法。这个方法在属性中插入了一个反向引用(如果它不存在的话),其名称存储在类T的A中。当系统执行一个删除时,这个方法也相应地删除反向引用,进而保证了不破坏参照完整性约束条件。
2.ODMGC++ 对象操纵语言例5.3显示了一段ODMGC++ 对象操纵语言代码,用来创建一个顾客对象。
intcreate_customer(Stringname,Stringaddress,Chainchain){
Databasechain_db.obj;
Database*chain_db=&chain_db.obj;
chain_db→open("Chain-DB");
d.TransactionTrans;
Trans.begin();
d_Ref<Customer>cust=new(chain_db,"Customer")Customer;
cust→name=name;
cust→address=address;
chain→members.insert_element(cust);
...Codetoinitializeotherfields
Tmit();
Chain_db→close();}程序首先打开一个数据库,然后开始一个事务,并用new操作符创建了一个顾客对象。在C++对象操纵语言中,类d_Object实现了C++内存分配操作符new的持久化版本,即在指定的数据库中分配对象的空间,而不是在内存中。new操作符的参数指明了被分配对象的类名和所在的数据库名。在初始化顾客信息的过程中,使用模板类d_Set<>提供的insert_element方法将顾客引用插入到连锁店会员集合members中。如果members声明为d_Rel_set类型,那么系统会自动建立反向引用。当有新的顾客加入或退出时,member会自动更新,加入或删除相应的引用。此外,ODMG还提供了一种机制来自动维护类的外延,以提供对象标识符的访问操作。类的外延作为数据库中该类模式的一部分。当对象被创建时,系统会将对象的标识符添加到对应类的外延当中;当对象被删除时,系统也会从类的外延中删除它的标识符。持久化C++系统提供了迭代器(Iterator)以方便对类的外延以及其他聚集型的类(如d_Set等)的集合中的对象进行遍历。当然,程序员也可以通过程序手动创建类的外延并进行维护。
3.ODMGC++对象查询语言例5.4查找所有积分超过1000人民币的顾客。
d_Set<d_Ref<Customer>>result;
d_OQL_Queryq1("SELECTc FROMCustomerc
WHEREc.get.point()>1000");
d_oql_execute(q1,result);上面的代码执行了一个OQL查询,结果存储在集合值变量result中。OQL是ODMG提供的对象查询语言,具有SQL的外观,书写比较方便。5.3.5持久化的Java系统基于Java的持久化扩展的面向对象数据库系统简称持久化的Java系统。ODMG管理组定义了在Java中支持持久化的标准。由于Java语言在内存管理上采用了与C++ 不同的机制,因而Java程序设计语言的持久化与C++ 程序的持久化支持模型有所不同。最大的不同是在Java中支持引用持久化的对象。在持久化Java系统中,不能直接创建持久化对象,而是通过在数据库中给对象命名为持久化的根(Root)来实现的。这些对象,以及所有由这些对象可达的对象都是持久的。如果一个类的对象引用自某个持久根,那么这个类必须被设定为可持久的。当一个事务想访问数据库中的对象时,它必须从数据库的一个根对象开始,通过对象名字来查询到它。引用持久化意味着持久化指针必须与瞬态指针是同类型的,所以Java里没有与C++ 中的d_Ref等价的模板类。引用持久化带来的另一个不同是,如果某个对象变成不能被数据库中所有的持久根到达,且没有任何活动事务存储了该对象的指针,则该数据库中的对象会变成垃圾。此类对象必须靠在数据库上定期运行一个垃圾收集过程来删除。垃圾收集一般和其他数据库活动并发运行。5.4对象—关系模型面向对象类型系统可以通过持久化程序设计语言将持久化及其他数据库特性加入到一个现存的程序设计语言中,与之相比较,通过扩展关系数据模型的方法可以提供一个包括复杂数据类型和面向对象的更丰富的类型系统,即对象—关系系统。在传统的关系数据模型基础上,提供数组、集合等复杂数据类型以及对这些复杂数据类型进行操作的能力,并提供具有继承性和对象标识等面向对象特点的数据模型,即对象—关系数据模型。对象—关系系统采用对象—关系数据模型,因此关系查询语言(特别在SQL中)需要做相应扩展以处理更加复杂的数据类型。这种扩展使得对象—关系系统同时保留了关系数据系统和面向对象数据系统的特征,同时也为试图使用面向对象特征的关系数据库用户提供了一个方便的迁移途径。5.4.1嵌套关系嵌套关系模型是关系模型的一个扩展。传统的关系模型都满足1NF的要求,即关系的所有属性都具有原子的域。如果某些记录的域值是一个集合或者是一个复杂结构,则不宜用1NF关系建模。在嵌套关系模型中,域的值可以是原子的也可以是关系。这样,元组在一个属性上的取值可以进一步分解,一个复杂对象就可以用嵌套关系的一个元组来表示。从而,嵌套关系模型中的数据对象可以和用户观念上的对象之间建立起一一对应的联系。例5.5在连锁超市经营管理系统中,店员的信息包括姓名、地址和电话,如果将这些信息定义为一个关系,那么下列一些域将是非原子的。
(1)地址:非原子属性,可进一步分为城市、街道和邮编。
(2)电话:非原子属性,有家庭电话、手机等多个号码。表5.2显示了用嵌套关系模型描述的店员信息,满足1NF的关系表如表5.3所示。由于1NF中只允许原子的域,因此每个电话号码均需要一个元组,地址信息用3个属性来存储。尽管不用嵌套关系也足以表达示例中的店员信息,但是嵌套关系可以产生一个更接近客观应用的模型。对地址信息而言,1NF设计会要求用户在他们的查询中指明每个字段,因此使得查询的书写复杂化。对电话信息而言,多值属性如果按照4NF进行分解,会带来大量的连接操作,因而也使系统更加复杂起来。表5.2嵌套关系的店员信息表5.3店员信息的一个1NF版本5.4.2复杂数据类型对象—关系模型可以通过嵌套关系模型进行扩展,在基本数据类型上提供元组、结构、集合等复杂数据类型,允许元组中的属性包含复杂数据类型,从而使对象—关系数据模型具有处理复杂对象的能力。本节介绍几种复杂数据类型,包括聚集类型、结构类型和大对象类型。有了这些复杂数据类型,就能够直接表达E-R模型的一些概念,而不需要转化为关系模型。在SQL2003标准中,类型定义要被记录在数据库模式中,而在持久化程序语言中类型定义不被保存在数据库中。
1.聚集类型聚集类型是一组相同类型元素组成的并且满足一定要求的集合,也称集合类型,可以分为以下几种类型:
(1)集合类型(SetType)是相同类型元素的无序、无重复的集合,如商品集合{书,本,电脑}。
(2)多重集合类型也称包集合(MultisetorBagType)是相同类型元素的无序、有重复元素的集合,如产品数量集合{75,80,75}。
(3)列表类型(ListType)是相同类型元素的有序、有重复元素的集合,集合中的元素可按位置操作,元素位置可变,如字符串类型就是列表类型的简化形式。
(4)数组类型(ArrayType)是相同类型元素的有序、有重复元素的集合,元素可按位置操作,但元素的位置不变,例如供应商名字组{王芳,李涛,魏一}。
(5)字典类型(DictionaryType)由<码,值>(<k,v>)对构成,是无序、k-v对的无重复的集合,一般用于码的索引结构。聚集类型由于是多个元素的集合,因此可以直接表述E-R图里的多值属性。对于有序的元素集合,可以采用数组类型或列表类型;对于无序的元素集合,可以采用集合类型或多重集合类型。
2.结构类型结构类型(StructuredType),也称元组类型(TupleType)或行类型(RowType),允许将元组中的一个属性定义为一个关系,并进行多次嵌套。例5.6在雇员类型中,属性date表示店员的出生日期,是一个MyDate类型,属性address表示店员的住址,是一个MyAddress类型。
CREATETYPE
MyDate(dayINTEGER,monthCHAR(10),
yearINTEGER)
CREATETYPEMyAddress
(zipcodeINTEGER,cityCHAR(10),
streetCHAR(20))
CREATETYPEEmployee(nameMyString,dateMyDate,addressMyAddress,phonesSETOF(MyString),salaryINTEGER)结构类型使得E-R图中的复合属性可以直接表达。结构类型还可以包含定义在其中的方法。将方法的声明作为一个结构类型的类型定义的一部分:
CREATETYPEEmployee(nameMyString,dateMyDate,addressMyAddress,phonesSETOF(MyString),salary
INTEGER)
METHODgiveraise(percentINTEGER)而方法的主体在类型定义以外单独创建:
CREATEMETHODgiveraise(percentINTEGER)FOREmployee
BEGIN
SETself.salary=self.salary+(self.salary*percent)/100;
END其中,变量self是指调用这个方法的结构类型的实例。方法的主体可以包含过程语句,详见5.6.3节。
3.大对象类型在新型的数据库应用中(尤其是多媒体数据库的应用中),有时需要存储很大的属性,如文档、声音、图像、视频等信息。因此,SQL2003标准提供了大对象类型(LOB,LargeOBject)来支持大对象的存储。根据其存储方式,大对象分为字符型数据大对象数据类型(CLOB,CharLargeOBject)和二进制数据大对象数据类型(BLOB,BinaryLargeOBject)。例如:
blog-articleCLOB(10KB)
photoBLOB(10MB)
filmBLOB(2GB)大对象一般用于外部的应用,通过外部的软件程序对它们进行检索和编辑。如文本编辑器UltraEdit可以对文档进行编辑,图像和视频编辑器Photoshop可以对图像和视频进行编辑。与数据库相比较,应用程序一般只检索大对象的“定位器”,通过定位器从宿主语言中操作该对象。例如,JDBC允许程序员分成片段来存取一个大对象,而不是一次全部取出来。5.4.3继承(类型继承、表继承)数据的泛化(Generalization)和细化(Specialization)是概念之间联系进行抽象的一种方法。当较低层面上的抽象表达了与之联系的较高层面上抽象的特殊情况时,则称较高层面上的抽象是较低层面上抽象的“泛化”,而较低层面上的抽象是较高层面上抽象的“细化”。这种细化的联系是一种“IS-A”的联系,即继承关系。在对象关系数据库中,继承可以在类型的级別上进行,也可以在表的级别上进行。本节先介绍类型的继承,然后介绍表的继承。
1.类型继承类型继承是类型相互间最基本的关联。在具有泛化和细化的对象类型之间,较高层的对象类型称为“超类型”(Supertype),较低层面上的对象类型称为“子类型”(Subtype)。子类型具有继承性,即继承超类型的特征,而子类型本身还具有其他的特征。例5.7设人的类型定义Person,用类型继承的方式定义学生和老师的类型Student和Teacher如下:
CREATETYPEPerson(nameMyString,social-securityINTEGER)
CREATETYPEStudent(degreeMyString,departmentMyString)UNDER
Person
CREATETYPETeacher(salaryINTEGER,departmentMyString)UNDERPerson其中,Student和Teacher都继承了Person的属性,即name和social-security,Student和Teacher被称为Person的子类型,Person是Student和Teacher的超类型。这种继承称为单一继承,即一个类型从一种类型继承而来。例5.8
设一个学校的助教既可以是学生又可以是老师,用类型继承的方式定义助教的类型TeachingAssistant如下:
CREATETYPETeachingAssistantUNDERStudent,Teacher其中,TeachingAssistant继承了Student和Teacher的全部属性,由于student和teacher都继承了Person的属性,根据继承的传递性,TeachingAssistant也继承了Person的属性。这种类型的继承称为多重继承,允许一个类型从多个类型继承而来。但是,由于department属性在Student和Teacher中分别都有定义,会引起多重继承的二义性冲突(在5.1.4节中有详细介绍)。例如一个助教可能是计算机系的学生同时又是自动化系的教师。为了解决多重继承的冲突问题,使用换名子句AS将它们重新命名,如下面的TeachingAssistant类型的定义所示:
CREATETYPEteachingAssistant
UNDERStudentWITH(departmentASstudent-dept),
TeacherWITH(departmentASteacher-dept)在SQL2003标准中,在类型定义的尾部有一个特别的字段,取值为FINAL或NOT
FINAL,用来标识是否可以从给定的类型创建子类型。关键字FINAL表示不可以创建子类型,NOT
FINAL则与之相反。
2.表继承表继承与E-R图概念中的“IS-A”联系相对应,子表(Subtable)的类型必须是超表(Supertable)类型的子类型,因此,超表中的每一个属性均出现在子表中。例5.9设有表people,用表继承的方式定义学生和老师的表students和teachers如下:
CREATETABLEpeople(nameMyString,social-securityINTEGER)
CREATETABLEstudents(degreeMyString,departmentMyString)UNDERpeople
CREATETABLEteachers(salaryINTEGER,departmentMyString)UNDERpeople其中,students和teachers称为people的子表,people称之为students和teachers的超表。超表people中的每个元组对应于子表students和teachers中的至多一个元组,在子表students和teachers中的每个元组也必须对应于超类people中的一个元组,即子表和超表中对于所有的继承属性具有相同属性值,这一性质称为继承的一致性约束。当一个查询用到people表时,它将查找的不仅仅是直接插入到这个表中的元组,而且还包含插入到它的子表students和teachers中的元组。但是,只有出现在People中的属性才可以被访问。如果要查找只在people中而不在它的子表中的元组时,需要使用关键字ONLYPeople来代替people。多重继承对于表来说也是可能的,可以定义一个teaching-assistants子表如下所示:
CREATE
TABLEteaching-assistants
UNDERstudentsWITH(departmentASstudent-dept),
teachersWITH(departmentASteacher-dept)其中,每一个在teaching-assistants中出现的元组也隐式地在表students和teachers中出现,从而也出现在people表中。多重继承也要满足一致性约束。在实际应用中,可以采用更为有效的方法存储子表,即不在子表中存放继承的属性(超表中的主键除外),因为这些属性值可以基于主码与超表的连接得到。当然,也可以在每个表中都存储所有继承的和局部定义的属性。当插入一个元组时,它仅仅存储在它被插入的那个表中,通过超表推断它的出现。因为不需要连接,所以第二种方法访问元组的属性会很快。但是,它可能导致信息重复,因为一个实体可能出现在两个子表中而不在它们的公共子表中出现。5.4.4引用类型面向对象的程序设计语言提供对对象的引用功能,即对象的属性类型可以是对一个特定类型对象的引用。例如:
member-listSETOF(REF(Customer))member-list即是一个Customer对象引用的集合。引用概念可以将数据类型定义中的实例映射扩充到类型值域中的实例映射,并提供有关细节的抽象。需要注意的是它与下面一条语句的语义区别:
member-listSETOF(Customer)对引用类型member-list而言,Customer是对象的引用语义,而对集合类型member-list而言,Customer是对象的拷贝语义。引用类型有两种实现方式,一种是对类型的引用,如引用类型member-list,另一种是对表中元组的引用。在SQL2003标准中,对一个指向表的元组的引用范围可以通过字段SCOPE来限制,例如:
shopheadREF(person)SCOPEemployee这里,shophead对Person的引用限制在Employee表中的元组。可以用表的主键实现对表中元组的应用,也可以让表中每一个元组都有一个元组标识符作为隐含属性。对元组的引用就是简单引用这个元组的标识符。子表隐含地继承这个元组标识符的属性,就像它从超表中继承其他属性一样。5.5与复杂类型有关的查询
SQL语句经过扩展可以处理复杂类型的查询,本节主要介绍基于关系值的属性查询、路径表达式的查询和聚组与析组。5.5.1基于关系值的属性用于计算关系值的表达式可以出现在关系名能够出现的任何地方,例如SELECT、WHERE和FROM子句。现以chain表为例,给出三组基于关系值属性的查询:
CREATE
TABLEchain(nameMyString,opendateMyDate,addressMyAddress,phonesSETOF(MyString),member-listSETOF(REF(Customer)))例5.10查找电话为“56781234”的连锁店。
SELECTnameFROMchain
WHERE"56781234"INphones在这个例子中,关系值属性phones出现在WHERE子句中,该属性所处位置在无嵌套关系的SQL中要求一个SELECT-FROM-WHERE的查询语句。例5.11找出每个连锁店中会员的名字。
SELECTB.name,Y.name
FROMChainasB,B.member-listASY这里,FROM子句中包含Chain和member-list,其中chain的member-list属性是一个以集合为值的字段,需要为其设置一个集合变量,然后加以引用。例5.12找出每个连锁店中会员的数目。
SELECTname,COUNT(member-list)FROMchain这里,chain的member-list属性以集合为参数并返回单个值作为结果,可以应用于任何以关系为值的SELECT子句中。5.5.2路径表达式路径表达式可以出现在查询的SELECT、WHERE和FROM子句中。现以master-students表为例,给出三组基于路径表达式的查询:
CREATETABLEmaster-students(advisorREF(People))UNDERpeople例5.13查找所有研究生导师的名字。
SELECT
FROMmaster-students这里,SELECT子句使用路径表达式,表示在表master-students中元组分量advisor的属性值name。其中,master-students.advisor为元组分量,其值为结构类型,因而可以用表示,各层次间用“.”分隔开来。例5.14查找所有连锁店的所有会员的名字。
(1) SELECTY.name
FROMchain.member-listASY
(2) SELECT
FROMchain其中,第一个写法在FROM子句使用路径表达式,第二个写法在SELECT子句使用路径表达式。由于member-list的属性值是集合类型,因此,不能直接写成,要为member-list定义一个元组变量,然后再加以引用。因此,第一种写法是正确的,而第二种写法是错误的。例5.15查找导师为“Zhang”的所有研究生名字。
SELECT
name
FROM
master-students
WHERE="Zhang"这里,WHERE子句使用路径表达式。由于advisor是一个对people元组的引用,上述查询中的name属性就是people表中元组的name属性。因此引用可以用来隐藏连接操作。如果没有使用引用,则master-students的advisor字段就会被声明为people表的一个外码,要找出一个研究生导师的姓名,就需要将master-students和people关系显式地做一个连接。使用引用则显著地简化了查询。5.5.3聚组与析组将一个嵌套关系转换为一个非嵌套关系的过程称做析组(Unnesting),也称做解除嵌套。通过查询语句可以实现对关系的析组过程。例5.16设关系employee有phones集合类型的属性,同时,还有一个结构类型属性date,析组SQL语句如下:
SELECTname,date.day,date.month,date.year,PASphones
FROMUNNEST(employee.phones)ASP其中,变量P被声明为以employee的集合类型属性phones为取值范围,结构类型date则被分解作为原子属性date.day、date.month和date.year。表5.2(见5.4.1节)显示了employee关系的一个实例,表5.3显示了经过析组查询后形成的符合1NF的关系。将一个非嵌套关系转换为一个嵌套关系的过程称做聚组(Nesting),也称做嵌套。嵌套可以通过GROUPBY的扩展来实现。通常,GROUPBY要对每个组创建一个临时的多重集合,然后在集合上应用聚集函数进行分组操作。在扩展的GROUPBY操作中,可以不通过聚集函数而直接将返回的多重集合作为一个嵌套关系。在例5.16生成的满足1NF的关系基础上,通过查询在属性date和phone上对关系进行嵌套:
SELECTname,(day,month,year)ASdate,SET(phone)
ASphones
FROMflat-employee
ROUPBYphone,date执行这个查询的结果如表5.3所示。在SELECT子句中通过子查询可以实现嵌套关系。一个与上面查询等价的查询如下:
SELECTname,
(SELECTphone
FROMflat-empASP
WHEREP.name=O.name)AS
phones,
(day,month,year)ASdate,
FROMflat-employeeASO系统对SELECT子句中对外部查询中的FROM和WHERE子句生成的每一个元组执行嵌套子查询,其中O.name用来确保对每一个雇员(这个例子假设没有重名的雇员,即name是employee的码)产生正确的联系电话号码集合。这种方法可以用来在嵌套查询上使用ORDERBY子句生成一个有序的结果。5.6函 数 和 过 程对象—关系系统允许定义函数、过程和方法来实现某些复杂操作。可以通过SQL的有关过程的组件,或外部的程序设计语言,例如Java、C或C++ 来定义函数、过程和方法。下面分别对这两种定义方法进行举例说明。5.6.1SQL函数和过程函数和过程对于特定的数据类型(比如图像和几何对象)处理十分高效,例如,比较两幅图形是否重叠以及它们的相似性。除此之外,当数据操作十分复杂时,函数和过程也十分必要,因为可以避免重复相同的动作。例5.17使用SQL的用户自定义函数计算连锁店的会员数目。
CREATE
FUNCTIONmember-count(one-chainChain)RETURNSINTEGER
AS
SELECT
COUNT(member-list)FROMone-chain函数member-count返回指定连锁店的会员数目。其中,Chain是类型名称,SELECT语句同关系one-chain(表示含有单个元组)一起执行,其执行结果是个单值,是一个单个属性的元组,其类型被转化为一个值。这个函数可以用于相应的查询,如返回具有多于1000个会员的所有连锁店名称的查询,其查询语句如下所示:
SELECTname
FROMcha
WHEREmember-count(cha)>1000其中,FROM子句中的cha是一个关系,在WHERE子句中被隐含地视为一个元组变量,因此可以用来作为member-count函数的一个参数。
member-count函数也可以写成一个过程:
CREATE
PROCEDUREmember-count-proc(INone-chainChain,OUT
a-count
INTEGER)
ASSELECT
COUNT(member-list)FROMone-chain过程调用可以放在SQL过程中,也可以放在嵌入式SQL中进行:
DECLAREa-countINTEGER;
CALLmember-count-proc(cha,a-count);
SQL函数和过程可以允许同名,但是同名的不同函数和过程的参数个数要不同。对于函数而言,如果有相同个数参数的同名函数,至少要有一个参数的类型不同。5.6.2外部语言程序函数和过程也可以通过外部程序设计语言进行定义(如C或C++)。这种方式定义的函数与SQL中定义的函数相比较有以下几个特点:
(1)外部语言定义的函数执行效率更高,实现功能更强。一些无法在SQL中执行的计算可以由这些函数执行,例如在一个元组的数据上执行复杂的科学计算。
(2)外部语言定义的函数需使用外部编译器,并通过数据库系统来装载和运行。这样,有些操作可能绕过数据库系统的访问控制,破坏数据库系统的一致性和完整性。这种情况下,数据库系统会将外部语言程序的代码作为一个单独进程的一部分来执行,通过进程间的通信对数据进行参数传递。
(3)外部语言定义的函数中如果存在错误的话,则可能破坏数据库的内部结构。在一些外部程序设计中(如Java),已经提供一些保护机制,阻止程序代码在数据库上直接执行任何读操作或者更新操作。外部语言编写的函数不同于嵌套SQL。嵌套SQL的查询是通过用户程序传递到数据库系统来运行的,查询结果一次一个元组地返回到用户程序。这样,用户编写的代码从不对数据库进行存取操作。而当调用一个外部语言编写的函数时,有两种运行方式:一种是函数代码在数据库系统上直接运行,一种是将函数所需的数据拷贝到一个独立的数据空间中再进行操作。毫无疑问,后者会引起非常高的开销,而前者将产生潜在的安全性和完整性问题。需要注意的是,外部语言过程由于需要处理空值和异常,因此它们必须具有几个额外的参数:一个指明操作状态失败或成功,一个存储函数返回值的参数,其余一些则作为指明每个参数或函数结果的值是否为空的指示器变量。5.6.3过程构造为了使SQL函数过程可以与外部语言函数功能相当,同时避免外部程序语言函数带来的潜在的破坏性,SQL2003标准提出了持久存储模块(PersistentStorage
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年创新科技园建设合伙合同
- 2024年健身场馆租赁合同
- 2024年定制葡萄酒瓶全球采购合同
- 2024年家电产品购销合同
- 2024年企业品牌重塑合作合同
- 2024年企业级防火墙技术支持合同
- 酒店HR数字化转型
- 音乐节自动售卖机运营合同
- 农场疫情防控管理方案
- 高温来袭防暑注意事项(5篇)
- 《会计平衡公式》教案
- 除尘器安装专业监理实施细则
- 八年级黄金矩形(数学活动)ppt课件
- 销售技巧个顶尖电梯销售技巧
- 《幼儿园卫生保健后勤材料资料》幼儿园保健医生每日检查工作记录表
- 葡萄糖生产教程
- 需求价格弹性案例分析
- 企业内部通信系统的设计与实现 计算机论文
- 重大决策合法性审查表.doc
- 信号集中监测系统(完整版)
- 复古风同学聚会邀请函.doc
评论
0/150
提交评论