需求分析与系统设计_第1页
需求分析与系统设计_第2页
需求分析与系统设计_第3页
需求分析与系统设计_第4页
需求分析与系统设计_第5页
免费预览已结束,剩余150页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、需求分析与系统设计 第9章 程序和事务设计 我们区分系统设计和程序设计。程序设计是系统设计中模拟程序的执行逻辑,定义客户机服务器对象合作的框架的那个部分。IS程序执行业务事务。假设一个事务的范围定义在程序之内的话,它就是DBMS可以维持的数据库一致性的一个单元。 第9章 程序和事务设计 程序和事务设计将系统设计制品放在一起,并作为系统设计过程的最终阶段。它将应用逻辑赋给GUI和数据库设计。它的结果是给程序员提供足够的程序设计指令,使他们能开始“裁剪代码”的设计文档。事实上,一些初步的代码可以从设计中自动生成(前向工程)。程序员对初始代码的扩展。可以逆向回溯到设计阶段,从而得到一个“双向”工程的

2、周期。 第9章 程序和事务设计 9.1设计程序 9.2程序导航 9.3设计事务 9.4双向工程 9.1设计程序 程序设计是完整的系统设计(第6章、7章和第8章)的一个内在部分。类包和构件的体系结构设计建立通用的执行框架。GUI和数据库的详细设计说明这个框架的前端和后端。程序设计填充通用框架中间的空缺,并将它转换为可以交给程序员去进行开发的设计文档。 9.1设计程序 程序设计一次集中在一个应用程序上。在这个意义上,程序设计是在第7章中讨论的用户界面设计的直接扩展。程序设计使用数据库设计的部分(子框架)(第8章),它还定义数据库过程方向的内容:存储过程和专用程序触发器。 9.1设计程序 程序的执行

3、逻辑划分为客户机和服务器过程。客户机过程具体化程序中大多数的动态对象合作(6.2节)。对象内聚和耦合(9.1.1节)的适当的平衡可以抑制合作的复杂度。尤其是,服务器过程更注重执好由客户机过程启动的业务事务。 9.1设计程序9.1.1类的内聚和耦合 9.1.2设计客户机服务器合作 9.1.1类的内聚和耦合 前面,特别是在第 5章和第 6章中,我们已经给出了好的程序设计的主要原理,虽然那是在好的系统设计的意义下说的。类分层是写出可理解、可维护的以及可控规模程序的基础。一旦将面向对象的程序交给投入者,该程序便会变成遗产程序。正确地使用继承和代理对避免这种情况是必需的。 9.1.1类的内聚和耦合 好的

4、程序设计要保证类的内聚和耦合的良好平衡。内聚和耦合这两个术语是由结构化设计方法创造的。然而,这两个术语在面向对象设计中具有相似的内涵和重要性。 类内聚是类的内部自我确定的程度,它度量类不与外界相关的强度。一个具有高内聚的类可以自己执行一个行为,或者达到一个单一的目标。内聚越强越好。 9.1.1类的内聚和耦合 类耦合是类之间的关联程度,它度量类的相互关系。耦合越弱越好(然而,类有时不得不“耦合”以便合作工作)。 内聚和耦合相互是不一致的。好的内聚意味着弱的耦合,反过来也一样。设计者的任务是使这两者之间达到一个最好的平衡。 9.1.1类的内聚和耦合 启发式规则 :两个类应该要么不依赖于另一个,要么

5、一个类应该只依赖于另一个类的公共接口。属件和与之相关的方法应该保存在同一个类中(这个启发式常常被其定义在公共接口许多存取者(get和set)方法所破坏)。一个类应该捕获一个且只捕获一个抽象。无关的信息,当其方法的一个子集作用到属性的一个真子集上,应该移到另一个类中。系统的智能应该尽可能一致地分布(从而使得类能够一致地分担同一项工作)。 9.1.1类的内聚和耦合 9.1.1.1类耦合的种类 9.1.1.2 Demeter法则 9.1.1.3存取程序方法和无智能类 9.1.1.4动态分类和混合实例内聚 9.1.1.1类耦合的种类 为了两个类之间能互相通信,它们需要被“耦合”。类X和类Y之间的耦合当

6、类X能够直接涉及到类Y时就存在了。八种类的耦合: 1.X从Y继承。 2.X具有类Y的属性。 3.X具有带上类Y作为参数的模板属性。 4.X具有将类Y作为输入参数的方法。 5.X具有将类Y作为输出参数的方法。 6.X知道类Y的全局变量。 7.X知道包含类Y的局部变量的方法。 8.X是Y的一个友元。9.1.1.2 Demeter法则 类耦合对对象通信是必需的,但是它应该尽可能被限制在类层的范围之内(即限制为层内的耦合)。层之间的耦合应该降到最低。在Demeter法则中给出了对限制类之间的任意通信的另一个方针,它说消息的目标只能是下面给出的对象:1.方法的对象本身。2.方法型构中的作为参数的对象。3

7、.由对象的属性所指的对象(包括在属性的集合中索引到的对象)。4.由该方法创建的对象。5.由全局变量代表的对象。 为了限制由继承引起的耦合,第三个规则可以局限于类本身定义的属性。被类继承的属性不能用来代表一个消息的目标对象。这个限制被认为是强Demeter法则。 9.1.1.3存取程序方法和无智能类 像在9.1.1节中所提到的那样,属性及其相关的方法应该保存在一个类中。一个类应该决定它自己的命运,一个类可以用将存取程序方法局限在它自己接口中的方法来限制其他类存取自己的状态。存取程序方法定义观察器(get)或变异器(set)操作(8.3.1.2节)。 9.1.1.3存取程序方法和无智能类 存取程序

8、方法将一个类“开放”,并由其他类来进行内部操作。虽然耦合蕴涵一定程度的开发,但过多地使用存取程序方法可能导致智能在类之间的不平衡分布。一个带有许多存取程序方法的类有变为无智能类的危险,其他的类决定什么对它来说是好的。 这就是说,存在这样的情况,一个类不得不对其他类开放。当存在实现两个或多个类之间的一种策略时,这种情况就会出现。这样的例子有很多。 9.1.1.3存取程序方法和无智能类 假设我们有两个类INTEGER和REAL,我们需要实现一个整数和实数之间进行转换的“策略”,那么这个策略应该在其中哪个类中实现呢?或者我们需要一个CONVERTER类来实现这个策略?采取任何一种方式,都至少有其中的

9、一个类必须允许存取程序方法,而且对这个策略而言它将变成是“无智能”。 9.1.1.3存取程序方法和无智能类 一个出自Jones的著名引证在这里是恰当的:“在一个面向对象的农场,有面向对象的牛奶。应该是面向对象的牛发送给面向对象的牛奶uncow_ yourself消息,还是面向对象的牛奶发送给自向对象的牛unmilk_yourself消息?” 。 例9.1(大学注册) 在第6章,我们已经为大学注册的部分需求设计了其中的合作部分。这个合作模型提供了相对统一的智能的分布,但是没有讨论其他的解决方案。 对这个例子,假设需要对一个课程增加一个学生。为此,需要做两个检查。第一,必须找出学习这个课程的前提条

10、件。第二,必须检查学生的学业记录以确定这个学生是否满足这个前提条件。有了这些信息,我们才可以决定这个学生是否能够增加到这个课程的学习中。 考虑由边界对象:EnrolmentWindow发送的消息enrol(),考虑三个类:CourseOffering、Course和Student来合作完成这个任务。我们的工作是设计一组可能的协作图来解决这个问题。讨论不同方案的利弊。 例9.1(大学注册) 图9.1说明了第一种方案。边界对象:Enrolmentwindow通过发送enrol()消息给aCourse.aCourse请求aStudent的学习记录,并对照它的前提条件进行检查来启动这个事务。aCour

11、se决定aStudent是否可以被汪册,并请求aCourseOffering增加aStudent到它的学生表中。 例9.1(大学注册) 图9-1中的情景赋予对象aCourse太大的能力。aCourse是策略的制定者,aStudent是个无智能类。这个方案是不平衡的但又没达到平衡的办法。 例9.1(大学注册)例9.1(大学注册) 我们可以将重心从aCourse转移到astudent,从而获得了图9-2所示的方案。现在,:EnrolmentWindow要求astudent做重要的工作。aStudent调用aCourse中的一个观察者方法getPrereq()。aStudent决定这次注册是否可能,

12、并命令aCourseOffering给这个学生注册。图9-3说明了一个较为平衡的解决方案,其中aCourseOffering是策略制定者。这个方案对aCourse和aStudent是公平的,但它却使这两个对象相当空闲和不用思考。ACourseOffering就像是“主程序”(Riel的说法中的一个“上帝”类。 例9.1(大学注册)例9.1(大学注册)例9.1(大学注册) 图9-3的方案可以得到改进,即引入一个控制对象来处理策略信息(参见BCE方法,5.2.4节)。图9-4中的控制对象:EnrolmentPolicy将这三个实体对象从注册策略中解放出来。这是有益的,因为注册策略的任何变化都封装在

13、这个单独的控制类中。然而,类EnrolmentPolicy也有变为“上帝”类的危险。 例9.1(大学注册)9.1.1.4动态分类和混合实例内聚 在第2.1.5.2.3节中,我们提出了动态分类的问题,并且观察到流行的面向对象程序设计环境并不支持它。缺乏这个支持的代价常常反映在设计出具有混合实例内聚的类。 Jones定义“一个具有混合实例内聚的类有某些对该类的一些对象来说没有定义的性质。”这种类的一些方法只能作用到其对象的一个子集上,一些属件只对对象的子集有意义。9.1.1.4动态分类和混合实例内聚 例如,类Employee可能定义了一些对象,他们可以是“一般的”雇员也可以是经理。经理是付年薪的,

14、然而向一个Employee对象发送PayAllowance的消息是没有意义的,因为可能这个Employee对象井不是经理。 9.1.1.4动态分类和混合实例内聚 为了消除这种混合实例内聚,需要扩展泛化层次来标识Employee的子类,如Ordinary mployee和Manager。然而,Employee对象可能今天是OrdinaryEmployee,明天就成为Manager,或者反之亦然。为了消除混合实例内聚,需要允许对象能在运行时动态地改变它所属的类公认的catch-22,如果不支持动态分类的话。 例9.2(大学注册) 考虑下面对例9.1的变化:晚上的课程只向非全日制学生提供。全日制学生

15、只可以注册白天的课程。如果非全日制学生要注册晚上的课程的话,要付少量的费用。非全日制学生当在一个给定的学期中注册了多于六个信用点(即一般要多于两个课程)时,自动考虑为是全日制的。 我们的任务是提出一个不带混合实例内聚的高内聚结构合作模型,然后仔细地评价这个模型,并提出和讨论另一个能避免动态分类问题的方案。 例9.2(大学注册) 为了消除混合实例内聚,需要将Student特化为两个子类PartTimeStudent和FullTimeStudent(图9-5),如果每个学生必须要么是非全日制的要么是全日制的话,类Student就是抽象的。消息payExtraFee(crs_off)将不会发送给类F

16、ullTimeStudent的对象,因为FullTimeStudent没有这样的方法。 例9.2(大学注册) 必须承认,这样仍然存在问题。一个非全日制的学生可能对白大的课程有偏爱(即evening_preference=False)并且没有额外要付的费用。换句话说,在 PartTimeStudent中仍有混合实例内聚问题。如果学生选择了白天的课程的话,向PartTimeStudent发送消息payExtraFee(crs_off)将没有意义。 例9.2(大学注册) 例9.2(大学注册) 图9-6扩展了这个设计来消除另一方面的混合实例内聚。类DayPrefPartTimeStudent没有方法p

17、ayExtraFee(crs_off) 。但是如果DayPrefPartTimeStudent因为白天的课程的没有更多的名额而不得不选择晚上的课程,又会怎么样呢?也许,要付某种其他的费用。应该再进一步特化从而导出类UnluckyDayPrefPartTimeStudent吗? 例9.2(大学注册) 例9.2(大学注册) 若不想进入一个荒谬的情景的话,我们可以选择放弃进一步推进消除混合实例内聚的想法。这里我们还没有提到动态分类,但实际上,属性current_sem_credit_points的当前值决定了一个学生是非全日制的还是全日制的。 例9.2(大学注册) 同样,一个学生在任何时候都可以改变

18、他对晚上还是白天的课程的偏好。如果缺少程序设计环境对动态分类的支持,那就是程序员的责任来让一个对象在运行过程中改变它所属的类。这是很困难的在永久对象的情况下,其对象OID值包含了类标识符时尤其困难。 例9.2(大学注册) 另一种方法就是限制继承层次的深度,消除对动态分类的要求,并重新引入一定数量的混合实例内聚。例如,我们可以允许一个对象根据属性evening_preference的不同取值用不同的方式去响应消息payExtraFee(crs_off),从而能够依靠图 9-5中的结构化合作,并解决含偏好晚上课程的问题。 例9.2(大学注册) 可以用一个if语句来编程,如下述伪代码所示:metho

19、d payExtraFee(crs_off) for the class PartTimeStudentif evenig_preference=False returnelsedo itend method 例9.2(大学注册) 虽然在面向对象代码中使用if语句表明了放弃继承和多态性,但从纯粹实际的原因来看它是不可避免的。与其费力地解决动态分类的问题,不如程序员给类引入了动态语义。一个对象根据它当前的局部状态对相同的消息用不同的方式去响应。状态图可以用来为这个类设计动态语义。不可否认的是,这个过程将承受类的内聚问题。 9.1.2设计客户机服务器合作 IS程序为了数据与数据库交互。客户机程序必

20、须使用数据库语言(通常是SQL)来存取和修改数据库。为了理解一个客户机程序如何与数据库服务器通信,需要认识到SQL可以用不同的形式出现并可以用于程序抽象的不同层次上。 9.1.2设计客户机服务器合作 图9-7区别了SQL接回的五个层次。在第一层,SQL用做DDL(数据定义语言)。DDL是一种规格说明语言,用于定义数据库的结构(数据库模式)。数据库设计者和数据库管理者(DBA)是第一层SQL的主要用户。 9.1.2设计客户机服务器合作 在第二层,SQL用做数据操纵语言(DML)或查询语言。查询语言这个术语有点用词不当,因为第二层上的SQL不仅用来检索数据用,还用来修改数据(带有插入、修改和删除操

21、作)。 9.1.2设计客户机服务器合作 使用第二层SQL的用户范围很广,从没有经验的专门用户到有经验的DBA。这一层上的SQL是交互式的,这意味着一个用户可以在程序设计环境之外构造一个查询,并让它立即在数据库上运行。第二层SQL是学习下面几层更精化的SQL的一个切入点。 9.1.2设计客户机服务器合作 应用程序使用第二层以上的SQL。在这些更高的层次上,SQL允许第二层上(作为惟一选择的)一次一个集合的处理机制仍然有效外,还允许一次一个记录的处理机制。一次一个集合的处理取一个或多个表(记录的集合)作为对一个查询的输入,并返回一个表作为输出。虽然这是一个很强的机制,但在复杂查询中使用却是困难和危

22、险的。 9.1.2设计客户机服务器合作 为了能肯定一次查询返回正确的结果,程序员必须有能力逐行浏览由查询返回的记录,并在一次一个记录的基础上决定对这些记录要做什么。这样的一次一个记录的处理能力称为光标,并在第二层之上的SQL中有效。 9.1.2设计客户机服务器合作 第三层上的SQL是嵌入在常规程序设计语言,如C和COBOL中的。因为程序设计语言编译器不理解SQL,需要一个预编译器来将SQL语句翻译成由DBMS供应商提供的DB库中的功能调用。程序员可以选择直接使用DB库函数来编程,在这种情况下就不需要预编译器了。 9.1.2设计客户机服务器合作 将客户机程序与数据库接口的一个流行方式是通过开放数

23、据库互连(ODBC)或Java数据库互连(JDBC)标准。要用这种方式的编程,要求有对特定DBMS的ODBC或JDBC软件驱动程序。ODBC和JDBC在SQL之上提供一个标准数据库语言,它被这个驱动程序翻译成简单DBMS SQL。 9.1.2设计客户机服务器合作 ODBCJDBC具有减轻本地DBMS SQL编程耦合度的优点。如果程序需要将来移植到不同的目标DBMS上,那么只要直接替换一下驱动程序就可以了。更重要的是,用ODBCJDBC可以支持向多于一个DBMS发布询问的应用。 9.1.2设计客户机服务器合作 ODBCJDBC的缺点是:它具有SQL的“最低公共特性”,客户机应用不能利用任何特殊的

24、SQL特性或者由特定DBMS供应商所支持的任何扩展。 9.1.2设计客户机服务器合作 第四层 SQL采用了与第三层 SQL同样的策略,将 SQL嵌入在客户机程序中。但第四层SQL提供更强的程序设计,应用生成器或第4GL(四代语言)。 4GL配置有“屏幕界面”和GUI构建能力。由于IS应用要求复杂的GUI,4GLSQL常常是构建这种应用的首选。 9.1.2设计客户机服务器合作 第五层SQL补充了第三层和第四层,它提供将一些SQL语言从客户机程序移向主动(可编程)服务器数据库的可能性。SQL用做程序设计语言(PLSQL)。服务器程序可以从客户机程序内进行调用,就像在下面将要讨论的那样。 9.1.2

25、设计客户机服务器合作9.1.2.1存储过程 9.1.2.2触发器 9.1.2.1存储过程 Sybase RDBMS首先引入存储过程,现在他们成为任何主要商用DBMS的一部分。存储过程将数据库变成一个主动可编程系统。 9.1.2.1存储过程 存储过程是用扩展的SQL编写的,它支持像变量、循环、分支和赋值这样一些程序设计构造元素。存储过程还可以被命名,可以有输入输出参数,它被编译并存储在数据库中。客户机程序调用一个存储过程就跟它调用子过程一样。 9.1.2.1存储过程 图9-8说明了客户机程序调用存储过程与向服务器发送完整的查询命令相比之下的优点。在客户机程序中构成的查询通过网络发送给数据库服务器

26、,这个查询语句可能包含语法和其他错误,但客户机不能消除这些错误,数据库系统是惟一可以做这种验证的地方。一旦被验证,DBMS检查调用者是否被授权运行这个查询。如果是,这个询问就被优化以决定对所需数据的最好的访问规划。只有这时它才能被编译、执行,最后将结果返回给客户机。 9.1.2.1存储过程 另一方面,如果询问(或者整个的询问的集合)被编写为存储过程,则它被优化并被编译进服务器数据库。客户机程序不需要在网络上发送(可能是很大的)询问取而代之的是它只要发送对这个过程名的一个短调用和一组实参。如果幸运的话,这个过程可能就驻留在DBMS内存高速缓存中。如果不是,它将从数据库中被调入内存。 9.1.2.

27、1存储过程 用户的授权也要像对SQL询问一样被检查。然后实参代替形参并且存储过程执行,最后结果返回给调用者。 9.1.2.1存储过程 就像在上述情景中看到的那样,存储过程提供了更有效的方式来从客户机程序中访问数据库。性能上的优点是由于网络堵塞的缓解,并且不需要每次收到客户机请求时都进行语法分析和编译。甚至更重要的是,存储过程由单独的地方维护,并可以供许多客户机程序来调用。 9.1.2.2触发器 触发器(8.4.1.4节)是一种特殊的存储过程,它不能被调用他们在一个数据库表上发生的插入、更新或删除等事件时将他们自己触发。这意味着每个数据库表可以最多有三个触发器。在某些系统中的确如此(如Sybas

28、e)。而在其他系统(如Oracle)中,因为可以标识出事件的其他变体,使得每个表可能有多于三个触发器(虽然这样,存在更多的触发器并不意味着它的触发器的表达能力就更强)。 9.1.2.2触发器 触发器可以被编程以加进作用在数据库上并且不能被任何客户机程序或者通过交互式SQLDML语句改变的任何业务规则。这意味着触发器可以超出引用完整性约束的过程性强制手段(如在第8.4.1.4节中所讨论的那样)。例如,一个触发器可以用来规定在某些时间段或某些天不允许访问数据库。 9.1.2.2触发器 客户机程序的用户甚至不会意识到触发器正监视着数据库中什么正在被修改。如果这个修改不违反业务规则,触发器对这个程序就

29、是不可见的。触发器只有当DML命令是不允许的时候才将自己暴露给用户。触发器将通知用户所出现的问题,它在程序屏幕上显示出错信息并拒绝运行这个DML操作。 9.2程序导航 主动数据库出现了,程序设计对象的数量就增加了,并且对象合作也变得更复杂。作为程序员可以以此为起点考察实现工作的设计文档的窗口导航图(7.6.2节)就显得不够了,它们需要扩展为(代换为)更完整的程序导航图。 9.2程序导航 程序导航图概念在UML中没有标准化或者说没有讨论。不过它是一种基本建模抽象,用来消除系统设计和系统实现之间的鸿沟。否则就是坏的软件工程程序的体系结构和逻辑没有文档化,而且留给程序员去决定。 9.2程序导航 9.

30、2.1构造型程序导航的活动图9.2.2程序导航图 9.2.1构造型程序导航的活动图 为了将窗口导航图转换为程序导航图,需要对UML的活动图增加服务器端的构造型。状态(圆角长方形)和活动(椭圆)都应该被构造型。构造型必须考虑DBMS模型或者甚至是特定DBMS的特性(这当然是为什么UML中没有提供这种导航图的主要原因或借口)。 9.2.1构造型程序导航的活动图 下面的构造型表可以用来用RDBMS设计程序导航。依赖于程序导航图所处的抽象层次,这个表可以缩小,或者用另外的对象来扩展:状态(数据对象):活动(程序对象):客户机SQL查询。9.2.1构造型程序导航的活动图 状态(数据对象):数据库。关系表

31、。列。记录。关系视图。列。记录。索引。簇。9.2.1构造型程序导航的活动图 活动(程序对象):存储过程。触发器。对插入操作的。对更新操作的。对删除操作的。其他种类的触发器。9.2.1构造型程序导航的活动图 客户机SQL查询。本地查询。DB库查询。ODBCJDBC查询。9.2.2程序导航图 为了说明程序导航图,我们将简单地扩展在7.6.2节中给出的窗口导航图。图9-9就是扩展(并进行了细微的调整)图7-23中的窗口导航图后得到的程序导航图。 程序导航图 9.2.2程序导航图 图9-9引入了两个服务器状态:Inventory Control()和Product(),增加了三个服务器活动:Selec

32、t Product()、 Update Product()和 On Update Product(),还增加了一个客户机活动Scroll()。 9.2.2程序导航图 通过所增加的信息,图9-9中的程序导航图告诉程序员,要在Product Browser中显示产品必须调用存储过程(Select Product)。当用户上下滚动浏览器窗口,这个窗口中的内容必须从数据库中更新时,也调用相同的存储过程。 9.2.2程序导航图 在这个图的下半部分,我们可以看到在 Update Product()中按下OK或Save键,就调用Update Product()。一个触发器控制输出的修改(On Update

33、Product)。 例9.3(关系管理) 考虑下述对例7.5(7.6.2节)的扩展:使用存储过程来修改(插入、删除、更新和完成)一个事件。需要有触发器来监控Event表上的插入和修改。 我们的任务是,为Contact Management应用中处理事件修改这部分设计程序导航图。 例9.3(关系管理) 这个例子的解决方案(图9-10)只涉及来自图7-24中与事件修改相关的那些客户机状态和活动。注意,存储过程Complete Event既可以从主窗口中也可以从对话框中调用。因为Complete Event要更新表Event,所以触发器On Update Event启动。同样的触发器也可以被存储过程

34、Save Event激活。 关系管理例9.3(关系管理) 对话框TaskEvent Details有双重的作用,既用来插入新的事件,又用来更新存在的事件。命令键OK调用存储过程Save Event。这个调用中的参数列表告诉这个过程OK是指插入还是指更新。对应地,这个过程的执行要启动两个触发器: On Insert Event或On Update Event中的一个。 9.3设计事务 事务是工作的一个逻辑单元,它包含一个或多个由用户执行的SQL语句。事务也是数据库一致性的单元,数据库的状态在事务完成之后还是一致的。为了保证这个一致性,DBMS的事务管理有两个作用:数据库恢复和并发控制。 9.3设

35、计事务 按照SQL标准,事务从第一个可执行的SQL语句开始(在某些系统中,要求有显式的 begin transaction语句)。事务结束于 commit或rollback语句。commit语句将变化永久地写入数据库中,而rollback语句擦除由这个事务带来的任何变化。 9.3设计事务 事务是原子的,这个事务中所有SQL语句的结果要么被承认要么被驳回。用户决定事务的期限(大小)。根据业务的需要,以及应用领域和用户-计算机交互风格,一个事务可以只有一条SQL语句那样短,它也可以涉及一系列SQL语句。 9.3设计事务 9.3.1短事务9.3.2长事务 9.3.1短事务 大多数传统的IS应用都要求

36、短事务。短事务包含一条或多条SQL语句,它们必须尽可能快地完成,从而使得其他事务不被挂起。 9.3.1短事务 考虑一个飞机预定系统,其中许多旅行代理为全球的旅客做航班预定。每个预定的事务必须快速由DBMS执行,以便使得该航班的空位信息能及时更新,从而数据库又可以处理等待在队列中的下一个事务,这是基本的。 9.3.1短事务9.3.1.1悲观的并发控制 9.3.1.2隔离的层次 9.3.1.3自动恢复 9.3.1.1悲观的并发控制 DBMS和ODBMS的异常都被构架为短事务。这些系统按照悲观并发控制来工作。事务要处理的每个永久对象都获取锁。有四种对象的锁:1.排它性(写)锁。其他事务必须等待,直到

37、持有这样一个锁的事务完成并将这种锁释放。2.更新(写意图)锁。其他事务可以读这个对象,但一旦有这样的需要,持有这种锁的事务被保证能够用排它的模式来对它进行升级。3.读(共享)锁。其他事务可以读并且可能获得对这个对象的更新后的锁。4.无锁。其他事务可以在任何时候更新对象,只适合于允许“受污染的读取”的应用,即一个事务要读的数据可以在这个事务完成之前就被修改或者甚至被(被另一个事务)删除。 9.3.1.2隔离的层次 与这四种锁相关联的是在并发执行的事务之间的四个隔离的层次。系统设计者的责仟是决定哪个隔离层次适合数据库上的事务的混合。这四个层次是:1.受污染的读取。2.不可重复的读取。3.幻影对象。

38、4.可重复读取。1 受污染的读取。 事务t1修改了一个对象但还没有承认这次修改,事务t2就读取了一个对象。如果t1回滚这个事务,则t2获得了一个数据库中从没有存在的一个对象。 2.不可重复的读取。 t1已经读取了一个对象,t2更新这个对象,t1再读取这个对象,但这次它获得这个对象的不同值。 3.幻影对象。 t1读取了一组对象,t2在这个对象集中插入一个新对象,t1重复这个读操作并将看到一个“幻影”对象。 4.可重复读取。 t1和t2可以并发执行,但这两个事务的交叉执行将产生同样的结果,就像它们是一次执行一个一样(这称为可序列化的执行)。 9.3.1.2隔离的层次 通常基于GUI的交互式IS应用

39、要求短事务。然而,在同一个应用中不同的事务的隔离层次可以不同。SQL语句set transaction可以用于这个目的。很明显这中间需要折中增加隔离的层次就减少了系统的全面并发性。 9.3.1.2隔离的层次 一个至关重要的设计决定与上面的考虑无关,事务的开始必须总是要被延迟到最后一秒钟。从客户机窗口开始一个事务,然后在它确实可以完成这个工作之前,必须让它一直等待到它从用户处获得了一些另外的信息,这一点是不可接受的。 9.3.1.2隔离的层次 用户可能要很长时间才能提供这些信息,或者甚至可能会在这个事务正在运行时关闭计算机。事务超时后就回滚回去,但对整个系统的吞吐量的危害己经产生了。 9.3.1

40、.3自动恢复 Murphy 法则说,如果什么事能够出错,那它就会的。程序可能含有错误,运行进程可能被暂停或者中断、动力供应可能失败、磁头可能断裂等等。幸运的是,DBMS为大多数情景提供自动恢复的能力。只有磁盘数据出现物理丢失的情况下,需要DBA的干预来命令DBMS从最近的数据库备份中恢复数据。 9.3.1.3自动恢复 根据事务在故障点的状态,DBMS将自动地执行回滚操作,或者一旦问题的原因被消除,再进行事务的向前滚动。这个恢复是自动的,但是一个DBA能够通过设置检查点出现的频率来控制恢复时间的长短。一个检查点强制DBMS暂时停止所有的事务并将所有的事务对数据库的改变(它上个检查点以来的)写进数

41、据库。 9.3.1.3自动恢复 图9-11示例了涉及从故障点进行自动恢复的问题。事务t1在检查点之后但在系统故障之前承认,由于DBMS不知道检查点之后的所有的改变是否都已经物理地写进数据库,它将在从故障中恢复之后;向前滚动(再做一次)事务t1。 9.3.1.3自动恢复 9.3.1.3自动恢复 事务t2在检查点和故障之间有一个回滚作用到它上面。同事务t1的情况一样,DBMS不知道这个被回滚的改变是否已经记入磁盘,DBMS将再进行一次回滚。 其他事务是在检查点之后开始的。事务t3将向前滚动以保证它的改变影响到数据库。同样,事务t4也将被重复,即回滚。 9.3.1.3自动恢复 事务t5不要求任何补救

42、行为,因为它在出现故障的时候正在运行。任何在故障之前由t5引起的改变还没有被写进数据库中,所有中间的改变也只是写进了日志文件。用户意识到在出故障时这个事务正在进行,可以在DBMS启动并再次运行时重新发送这个事务。 9.3.1.4可编程的恢复 没有预见的系统故障由DBMS自动恢复,然而设计者和程序员应该控制任何可预见的事务问题。DBMS提供一组到程序上的回滚选项以使得它可以从问题中平缓地恢复,从而可能使用户意识不到在什么地方出了问题。 9.3.1.4可编程的恢复 首先,GUI指南,如用户控制或宽容原则(7.3节),要求程序允许用户出错并从中恢复。一个程序员控制的作用在程序正确的位置上的回滚可以将

43、数据库恢复到以前的状态(即撤消错误),假如这个事务还没有被确认的话。 9.3.1.4可编程的恢复 如果这个事务已经确认,那么程序员还可以选择写一个补偿事务。用户然后可以请求执行这个补偿事务来撤消对数据库的改变。补偿事务特别设计来允许可编程的恢复,并应该在用例中建模。 9.3.1.4可编程的恢复 9.3.1.4.1保存点 9.3.1.4.2触发器回滚 9.3.1.4.1保存点 保存点是程序中的一个语句,它将一个较长的事务划分成几个小的部分。被命名的保存点插在程序的战略性的关键位置上。程序员就可以选择将进程回滚到某个被命名的保存点上,而不是回滚到事务的开始。 9.3.1.4.1保存点 例如,程序员

44、可以在update操作之前插入一个保存点。如果update失败,程序回滚到这个保存点并试图再执行更新操作。或者,程序可能采取另外的行为来避免放弃整个事务。 9.3.1.4.1保存点 在较大的程序中,可以在每个子程序之前都插入保存点。如果子例程失败,就可以回滚到这个子过程之前再用改过的参数来执行它。如果必要的话,需要一个特别设计和编程的恢复子例程来做这个扫尾工作,以便使得这个事务能恢复执行。 9.3.1.4.2触发器回滚 触发器回滚是一种特殊的保存点。就像在9.1.2.2节所解释的那样,一个触发器可以用来编程任意复杂度的业务规则。有时当一个触发器拒绝修改一个表(由于这个事务试图打破业务规则)时并

45、不想撤消整个事务。这个事务可能想要采取补救行为。 9.3.1.4.2触发器回滚 针对上述原因,DBMS可以提供编写触发器的可能以回滚整个事务或只回滚这个触发器。在后一种情况下,程序(可能是一个存储过程)可以分析这个问题并决定进一步的行为。甚至如果整个事务不得不被回滚,程序可能更好地解释这个错误的原因,并向用户显示更有智能的消息。 9.3.1.5设计存储过程和触发器 程序导航图(9.2.2节)可以进一步扩展以包括事务状态。然而,从图形分布的观点来看这非常麻烦,另一个解决办法可以是设计多个程序导航图,每个都代表了导航的不同角度。其中有一个这样的角度重点在捕获事务的导航。 9.3.1.5设计存储过程

46、和触发器 在任一情况下,程序导航图都确定了存储过程和触发器,还需要提供每个存储过程和触发器的目的、定义和详细设计。特别地,需要部署一些伪代码表示法来定义算法。 9.3.1.5设计存储过程和触发器 作为一个例子,我们下面给出关系管理应用(参见图 9-10和 9.2.2节)中的存储过程DeleteEvent的一个算法。这个过程检查正试图删除事件的用户(雇员)是否与创建这个事件的是同一个用户。如果不是,这个删除操作就被拒绝。这个过程还检查这个事件是否已经是当前任务剩下的惟一事件。如果是,这个任务也被删除。 9.3.1.5设计存储过程和触发器 BEGININPUT PARAMETERS(event_i

47、d,user_id) Select Event(where event_id = event_id) IF user_id = Event.created_emp_idTHENdelete Event(where event_id = event.id) IF no more events forTask.task_id = Event.task_id ANDEvent.event_id = event_idTHENdelete that TaskEnD IFELSEraise error(Only the creator of the event can delete that event)

48、ENDIFEND9.3.1.5设计存储过程和触发器 存储过程DeleteEvent包含delete语句来从表Event和Task中删除记录。这些delete语句将启动对这些表的删除触发器(如果有的话)。如果这些触发器的算法超出了正常的引用完整性检查范围,设计者还应该为它们提供伪代码规格说明(包含对回滚策略的决定是触发器回滚还是事务回滚)。 9.3.2长事务 一些IS应用的新的类鼓励用户之间的合作。这些应用被认为是工作组计算应用或者计算机支持协同工作(CSCW)应用。这方面的例子包括许多办公室应用、协同写作、计算机辅助设计、CASE工具等。 9.3.2长事务 工作组计算应用在很多方面都有对与带短

49、事务的传统数据库模型正交的数据库需求,传统数据库模型将用户分隔开,而工作组计算应用要求长事务、版本管理、合作并发控制等。 9.3.2长事务 ODB模型为工作组计算提供一个框架,并且许多ODBMS产品是针对这个应用领域的。工作组计算应用的用户共享信息,并且能意识到他们正在进行的工作是在共享的数据上进行的。他们使用个人数据库在他们自己的工作空间上工作,这个数据库由从公共工作组数据库(备份)中选出来的数据组成。他们在一个长事务中工作,这个长事务能够跨越几个计算片段(用户能够中断,然后又可以返回,继续在同一个长事务中工作)。 9.3.2长事务 长事务的主要方面是,它不允许因为故障而在没有系统提供轨迹的

50、情况下自动回滚。为了认识这个需求的重要性,可以想像如果由于计算机故障,这本教科书现在要被“回滚(撤消)”时我的失望情绪!长事务的撤消由用户通过保存点来控制的,保存点永久性地存储了用户私有数据库中的对象。 9.3.2长事务 短事务的概念并没有从工作组计算中完全去除。短事务对在保证组数据库和私有数据库之间的检出和检入操作的原子性和相互隔离是必需的。短锁于是就被免除了,并且长的永久锁则由组数据库作用到所有检出的对象上。 9.3.2长事务 长事务模型的相关的目标包括:允许合作的用户之间的信息交换(甚至如果暂时不一致)。检测数据的不一致并促成达成决定。利用对象的版本性来控制共享,不丢失系统故障情况下的工

51、作。 9.4双向工程 现代软件生产的迭代增量式过程(1.1.3.1节)要求来自设计和实现之间的双向工程的强有力的支持。双向工程定义为向前的代码产生和从代码到设计模型的逆向工程的组合。双向工程给出了“用图形或文本视点工作的能力,工具保持了两种视图的一致性” 。 9.4双向工程 在客户机服务器应用中,双向工程可以单独作用在客户机应用程序和服务器数据库程序上。也许实际上是很可能的,不同的 CASE工具用于同一个项目的客户机设计和服务器设计。还有,用于双向工程的 CASE工具必须紧密地与特定的客户机和或服务器程序设计环境集成在一起。 9.4双向工程 9.4.1客户机程序的双向工程9.4.2数据库的双向

52、工程 9.4.3从关系数据库到对象关系数据库的再设计工程 9.4.1客户机程序的双向工程 客户机应用的双向工程的原理相对来说比较直接但问题出在细节中。图9-12是一个面向对象程序设计语言的双向工程的典型周期的活动图。UML模型存储在CASE资源库中(就像在前面解释的那样,CASE资源库本身是一个数据库系统,常常是一个对象数据库)。 9.4.1客户机程序的双向工程 UML Design Model(一个UML状态)不得不特别针对程序设计语言来开发。Code Generation(一个UML活动)使用UML Design Model来产生Source Code(头文件和实现文件)。任何用户提供的定

53、义和来自前一个双向工程的附加声明被保留下来。 9.4.1客户机程序的双向工程 Source Code后来经过正规程序设计的改变和扩展。Modified Code在图9-12中称为UML Generation的活动UML Implemented Model的逆向工程。某种形式的可视化Model Differencing工具然后用来比较当前的UML Implemented Model和最新的UML Design Model,从而揭示设计产生的改变。所有被接受的改变都传播到UML Design Model中,并且开始双向工程的下一个循环。 9.4.1客户机程序的双向工程 9.4.1客户机程序的双向工

54、程 就像前面所观察到的,问题出在细节中。实践中,在 CASE工具对程序设计语言的理解和对这个语言的特定的编译器之间还有许多“遗漏的链接”。CASE工具可能对编译通过的代码报告分析错误,因为它可能不能识别由特定编译器支持的语言的变体。 9.4.1客户机程序的双向工程 CASE工具可能不能解决一些对特定编译器的声明或特定库源文件的引用。例如,如果源文件引用到在另一个文件中定义的符号,但没有显式地包含这个文件时,这个引用就不能被解决。虽然存在对许多这样的问题的工作区,但它们肯定会导致不恰当的解决方式,需要手工进行调整。 9.4.1客户机程序的双向工程 这就是说,引起不恰当并不是不对客户机程序进行双向

55、工程的理由,这种不恰当可以用手动方式来改正,一旦改正UML模型就得出了与当前程序匹配的文档。否则就会完全失去对应用实现的控制。 9.4.2数据库的双向工程 数据库的双向工程在设计端涉及物理数据模型(PDM),在实现端涉及数据库(DB)。PDM模型用来代替UML,因为UML不支持物理数据库设计(8.4节)。PDM模型必须针对特定的DBMS。 9.4.2数据库的双向工程 图9-13是关系数据库的双向工程的一个活动图。在数据库的PDM模型构造之后(状态Initial PDM),就可以被存档(活动Archive)。比较已经存档的和当前的PDM支持捕获该模型的最新修改。 9.4.2数据库的双向工程 9.

56、4.2数据库的双向工程 从Initial PDM到Initial DB的前向工程由活动Create DB完成。这个活动产生一个DB模式,包括触发器。 Initial DB通过递归活动Load来填充数据。活动Modify DB引入模式的改变并引起到状态Current DB的数据库迁移。 9.4.2数据库的双向工程 在这个阶段,有两种可能性存在:对Current PDM的改变可以与产生Current DB同步(活动Synchronize PDM with DB)或者反之亦然,即对Current DB的改变也可以与产生Current PDM同步(活动 Synchronize DB with PDM)。结果, Current PDM可能需要存档并且Current DB也需要在重装。 9.4.2数据库的双向工程 图 9-14显示了从Current DB(Sybase DB)到Current PDM(PowerDesigner PDM)的逆向工程一个片段(活动Synchronize PDM with DB)的一个屏幕。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论