数据库管理            本章学习目标: ● 理解数据库管理的必要性和重要性 ● 学习处理数据库的各种方法 ● 理解并发控制、安全性、备份和恢复的必要性 ● 学习解决多用户同时处理数据库时出现的常见问题 ● 学习使用锁定,理解死锁的概念 ● 了解乐观锁定和悲观锁定的区别 ● 理解ACID事务的意义 ● 学习1992 ANSI四个标准隔离级别 ● 理解安全的必要性并学习提高数据库安全的具体措施 ● 了解通过重新处理和回滚/前滚进行恢复的区别 ● 理解通过回滚/前滚执行恢复操作的实质 ● 了解基本的DBA管理功能 ● 理解分布式的数据库处理 ● 理解对象-关系数据库的概念                                    本章的主要任务是介绍了一个重要的业务功能,称之为数据库管理(DBA)。它的目的是对数据库进行管理,以便最大程度地发挥数据库对其所属机构的作用。通常情况下,这意味着需要在实现两个矛盾的目标之间取得平衡,即保护数据库与面向用户扩大数据库的可用性和功能之间的矛盾。两个术语“数据管理(data administration)”和“数据库管理(database administration)”目前都在使用。有时候,可以认为这两个术语表示相同的意思;在某些情况下,它们的含义又是不同的。最常见的情形是,数据管理指的是应用于整个组织的功能,它是一个面向管理的功能,主要关注的是公司数据的隐私和安全问题。而术语数据库管理指的则是一个更为技术性的功能,面向的是特定的数据库,包括处理该数据库的应用程序。本章将重点介绍数据库管理的问题。   不同数据库的规模和涉及范围相差很大:从单个用户的个人数据库到大型的跨机构的数据库(如一个航空订票系统)。尽管管理任务会因为数据库的大小、复杂性和应用的不同而有所差异,但是所有的数据库都需要管理。例如,对个人数据库来说,用户只要备份数据,维护并保持文档记录为最少。在这种情况下,使用数据库的用户其实也执行了DBA(Database Administration,数据库管理)功能,尽管用户本身可能没有意识到这一点。   对于多用户的数据库应用程序来说,数据库的管理会变得更加重要和复杂。因而,需要对其加以重视。对于有些应用程序来说,一两个兼职人员就可以实现这一功能。对于更大的Internet或内部网数据库,即使是全职的人员来负责数据库的管理,也会非常耗时,而且需要应付太多的变化情况。维护拥有上百或上千用户的数据库需要相当多的时间、技术知识、管理技术和熟练的技能。这样的数据库一般是由数据库管理部门来维护的。这时,这个部门的经理称为数据库管理员(database administrator);缩略语DBA可以指这个部门,也可以指其经理。   DBA总的职责在于帮助数据库的开发与使用。这通常意味着需要平衡一个矛盾:保护数据库与向用户扩大数据库的使用和好处的矛盾。DBA主要负责数据库及其应用程序的开发、运行和维护。   本章将详细介绍数据库3个重要的管理功能:并发控制、安全性、备份和恢复。然后将简单总结为什么需要配置变更管理。最后,还将讨论两个先进的数据库话题:分布式数据库以及面向对象的数据库系统。   在介绍上述内容之前,首先要为Heather Sweeney Designs公司创建数据库(本书已在前面的章节中以此作为数据库建模和数据库设计的示例进行讨论了)。本章和本书第7章仍将使用该示例作为一个示例数据库。 6.1 Heather Sweeney Designs公司的数据库   图6-1给出了使用SQL Server 2005语法创建Heather Sweeney Designs公司(称作HSD)数据库的SQL语句。该SQL语句是从图5-24中HSD数据库设计中得到的,列的约束来自于图4-21中的属性说明,参照完整性约束如图5-25所示。   图6-2给出了用于填充HSD数据库的SQL语句,同样也是用SQL Server 2005语法编写的。最后,最终得到的HSD数据库如图6-3中SQL Server 2005 Express Edition中的图形所示。 图6-1 创建HSD数据库的SQL 语句 图6-1 (续) 图6-2 用来填充HSD数据库的SQL 语句        图6-2 (续)       图6-2 (续) 图6-2 (续) 图6-3 SQL Server 2005 Express Edition中的HSD数据库 控制、安全和可靠的必要性   从单用户数据库到大型的跨机构数据库(如航空订票系统),不同的数据库在大小和涉及领域方面存在巨大差异。如图6-4所示,它们在处理方式上也有所不同。 图6-4 数据库处理环境   本书将在第7章中讨论数据库处理应用程序时详细定义和讨论图6-4中所给出的各种环境。至此,只需要知道图6-4中所有的应用程序元素都可以在同一时间内运行即可。当Web页面ASP(Active Server Pages)和JSP(Java Server Pages)访问数据库时,可能会生成查询、表单和报表,也可能会执行存储过程。在COBOL、C#以及其他程序设计语言中运行的传统应用程序也可能正在处理数据库的事务。所有这些操作都可能会导致编程代码存储到DBMS中——这是将在本书第7章中讨论的触发器和存储过程。同时,当所有这些程序都在运行时,必须执行这些约束(如参照完整性约束)。最后,数据库的用户可能会达到上百甚至上千,他们可能需要一周7天、一天24小时不间断地处理数据库。   所以,有必要引入3个数据库管理功能,以管理有可能出现的混乱。首先,必须控制并发用户的操作,确保其操作所产生的结果与期望的结果一致。第二,必须在适当的时候执行安全措施,在适当的时候只有经过授权的用户才可以执行授权的操作。最后,在数据库出现故障时,必须运行备份和恢复技术和程序来保护数据库,从而在必要时能快速而精确地恢复它。我们将依次考虑以上这些情况,在第7章中还将看到在使用Web应用程序访问数据库的时候已经开始使用这些管理功能了。 6.2 并发控制   并发控制的目的是保证一个用户的工作不会对另一个用户的工作产生不合理的影响。在某些情况下,这些措施保证了当该用户和其他用户一起操作时,所得到的结果和他单独操作时的结果相同。在另一些情况下,这表示用户的工作按预定的方式受到其他用户的影响。   例如,在一个订货系统中,用户应该能够访问一个订单,无论此时是否有其他用户访问该订单,或者同时有上百个用户在访问,所得到的结果都相同。另一方面,如果用户希望打印一份最新的存货清单,他就可能需要得到其他用户目前正在改动的数据,即使这些改动以后可能会被取消。   遗憾的是,还没有一种并发控制技术或机制可以处理所有的情况。它们都有利有弊。例如,用户可以通过锁定整个数据库而得到非常严格的并发控制,但是在这个用户进行处理时,其他任何用户都不能执行任何操作了。这是严格的保护措施,但是这样做的代价也非常高。正如您将看到的,也可以采取其他措施,可能这些措施更难通过编程的方式实现或执行,但是可以得到更多的吞吐量。当然,还有其他一些扩大吞吐量的措施,但也只是对低层次的并发控制而言。设计多用户数据库应用程序时,开发人员必须权衡这些利弊。 6.2.1 使用原子事务的必要性   在大多数数据库应用中,用户都以事务的形式提交工作,事务也称为逻辑工作单元(logical units of work,LUW)。事务(或LUW)是对数据库执行的一系列操作,这一系列操作或者全部成功运行,或者是不执行其中任何一个操作。在后一种情况下,数据库保持原样。因为这些事务是以单元的形式执行的,所以有时把这样的事务称为原子(atomic)事务。在记录新的订单时,请考虑以下的一系列数据库操作:   (1) 修改客户记录,增加Amount Owed值。   (2) 修改销售员的记录,增加Commission Due值。   (3) 将新的订单记录插入到数据库中。   假设最后一步可能由于文件空间不足而失败。如果前两个改动都得以执行,而第三步却失败了,设想这样可能引起的混乱。客户可能被要求付款,而他从来没收到过这个订单;销售人员可能会收到关于这个订单的佣金,而订单并没有送给客户。很明显,这3个操作需要作为整体来执行:或者全部执行,或者都不执行。   图6-5比较了下面两种情况的结果:将这些操作作为一系列独立步骤来执行(见图6-5(a)),以及作为原子事务来执行(见图6-5(b))。注意,当自动执行这些步骤而其中一个步骤失败时,则表明没有对数据库做任何改动。同时,还应注意应用程序必须使用命令Start Transaction、Commit Transaction和Rollback Transaction等来标记事务逻辑的边界。对于不同的DBMS产品,这些命令的形式有所不同。 图6-5 应用一系列操作事务和多个步骤事务的结果比较 6.2.2 并发事务处理   如果一个数据库同时处理两个事务,则称这两个事务为并发事务。尽管可能在用户看来好像是同时处理这些并发事务的,但实际情况并不是这样,因为处理数据库的机器的中央处理器(CPU)一次只能执行一个指令,因此通常这些事务是交叉执行的,也就是说,操作系统在不同任务之间来回切换CPU服务,这样在给定时间间隔内执行其中一个事务的某个部分。任务之间的切换非常快速,所以如果有两个人并排坐在浏览器前,同时对同一个数据库进行处理,可以相信他们的事务是同时完成的。但是,事实上这两个事务是交叉执行的。   图6-6显示了两个并发的事务。用户A的事务是读取并修改Item 100,再将其重新写入数据库中。用户B执行相同的操作,但对象是Item 200。CPU处理用户A的事务,直到它必须等待读取或写入操作完成,或者等待其他的操作完成。然后,操作系统切换到用户B的控制上。然后,CPU开始处理用户B的事务,直到发生类似的对事务处理的中断,这时操作系统又将控制权转回到用户A上。同样的,对用户来说,这一处理过程看起来是同步的,但它实际上是交叉执行的,或者说是并发的。 图6-6 两个用户的任务并发处理的示例 6.2.3 丢失更新问题   因为用户在处理不同的数据,所以图6-6所示的并发处理不会出现什么问题。但是假设两个用户同时都希望对Item 100进行操作。例如,用户A希望订购5套Item 100,而用户B则希望订购3套。   图6-7描述了这个问题。用户A读取Item 100的记录,该记录传送到用户的工作区。根据记录,还有10套存货。然后,用户B读取Item 100的记录,这些数据又传送到该用户的工作区。同样,根据记录,还有10套存货。现在用户A提取其中的5套,在他的用户工作区中将存货数目减为5,并将记录重新写入Item 100。用户B提取了3套,在他的用户工作区中将存货数目减为7,并将记录重新写入Item 100。这样数据库将出现错误,显示还有7套Item 100库存。回顾该流程,开始库存是10,用户A提取了5套,用户B提取了3套,数据库最后显示库存中还剩7套。显然,这是错误的。   在两个用户刚获得数据时,这些数据是正确的。但是,当用户B读取记录时,用户A已经有了需要更新的副本。这种情况称为丢失更新问题(lost update problem)或并发更新问题(concurrent update problem)。另一个类似的问题称为非一致读取问题(inconsistent read problem)。在这种情况下,用户A读取的数据已经被用户B的部分事务处理过。其结果是用户A读取了错误的数据。 图6-7 丢失更新问题的示例 6.2.4 并发问题:脏读取、不可重复读取和幻象读取   并发处理有可能引起一些问题,这些问题都有其标准化的名字:脏读取、不可重复读取和幻象读取。当一个事务读取了一个尚未提交到数据库但已经过修改的记录时,这种情况称为脏读取(dirty read)。比如,在下面的情况中就会发生脏读取:如果一个事务读取一行数据,而这行数据被另一个事务修改过,但是后来第二个事务又取消了修改。如果事务重新读取以前读取过的数据,并且发现另一个事务对其进行了修改和删除,这称为不可重复读取(nonrepeatable read)。当事务重新读取数据,但发现在读取该数据后已有另一事务插入了新的数据行,这就称为幻象读取(phantom read)。 6.2.5 资源锁定   可以通过一种办法来弥补由并发处理引起的不一致问题,即在将要修改某些数据行或表时禁止多个应用程序同时获取这些行或表的副本。这个方法称为资源锁定(resource locking)。该方法是锁定将要更新的数据,从而禁止共享,这样就防止了并发处理问题的发生。图6-8给出了使用锁定命令的处理步骤。   因为数据被锁定,用户B的事务必须等待,直到用户A处理完Item 100的数据为止。在运用该策略后,只有在用户A完成对Item 100的修改后,用户B才可以读取Item 100的记录。在这种情况下,最终保存在数据库中的Item 100的数目是2,这才是正确的数字(一开始的数据是10,然后A取走5,B取走3,最后剩下2)。 图6-8 带有显式锁定的并发处理示例   锁定可以由DBMS自动执行,也可以由应用程序或查询用户发给DBMS的命令执行。DBMS执行的锁定称为隐式锁定(implicit lock);而命令执行的锁定称为显式锁定(explicit lock)。   在前面的示例中,数据行被锁定。但是,不是所有的锁定都应用在这个级别上。一些DBMS产品的锁定针对的是页面级,有些针对表,有些则针对数据库。锁定的规模称为锁定粒度(lock granularity)。对于粒度较大的锁定,DBMS容易管理,但是经常引发冲突。而较小粒度的锁定则不易管理(DBMS需要跟踪和检查许多细节内容),但是较少引发冲突的情况。   锁定也因类型的不同而各异。排它锁定(exclusive lock)可以锁定对产品项的任何类型的访问。其他任何事务都不可以读取或修改数据。共享锁定(shared lock)锁定的是正在修改的产品项,但是不拒绝对数据的读取。这就是说,其他事务可以读取被锁定的产品项,只是不能修改数据。 6.2.6 串行化事务   并发处理两个或多个事务时,所得数据库的结果在逻辑上应该和事务以任意串行方式处理后所得到的结果保持一致。以这种方式处理并发事务的模式称为串行模式。   实现串行化的方式有许多种。一种方式是使用二段锁定(two-phased locking)处理事务。采用这种策略时,事务可以根据需要决定是否使用锁定,但是一旦释放了第一个锁定,就不可以再使用其他任何锁定。因此,事务就有一个增生阶段(growing phase),即获取锁定的阶段,还有一个收缩阶段(shrinking phase),即释放锁定的阶段。   许多DBMS产品使用一种特殊的二段锁定。如果使用了这类锁定时,那么在事务的执行过程中都可以进行锁定,但是直到发出COMMIT或ROLLBACK命令时才能释放锁定。这种策略比二段锁定的要求更严格,但更容易实现。   考虑一个订货事务,该事务涉及处理CUSTOMER表、SALESPERSON表和OREDER表中的数据。为了确保数据库不会因为并发行为而产生异常,订货事务在需要时可以锁定CUSTOMER表、SALESPERSON表和ORDER表,修改所有的数据库,然后释放所有的锁定。 6.2.7 死锁   尽管锁定解决了一个问题,但同时也产生了另一个问题。考虑两个用户都希望从库存中订购两个产品项时可能发生的情况。假设用户A希望订购一些纸张,如果她可以得到纸张,则可能还需要再订购一些铅笔。同样假设用户B希望订购一些铅笔,如果他可以得到铅笔,也可能需要再订购一些纸张。处理过程如图6-9所示。   在图6-9中,用户A和用户B都被锁定的状态称为死锁(deadlock),有时称为致命包含(deadly embrace)。其中每个用户都在等待另一个用户已经锁定的资源。解决这个问题通常有两种方法:阻止死锁发生,或者允许死锁发生,然后打开该死锁。 图6-9 死锁示例   有多种方式可以防止死锁的发生。一种方法是允许用户一次只发出一个锁定请求;事实上,用户必须立刻锁定当前所需的所有资源。如果示例中的用户A一开始就同时锁定了纸张和铅笔记录,则死锁无论如何不会发生。第二种防止死锁的方法是规定所有应用程序锁定资源的顺序必须完全相同。   几乎每一个DBMS都有检测死锁的算法。当死锁发生时,一般的解决方法是回滚其中的一个事务并取消它对数据库所做的改动。 6.2.8 乐观锁定和悲观锁定   激活锁定的方式一般有两种。没有冲突发生时采用乐观锁定(optimistic locking)。读取数据,处理事务,执行更新,然后检查是否发生冲突。如果不存在冲突,事务就可以完成。如果存在冲突,则重复事务,直到没有冲突。采用悲观锁定(pessimistic locking)时,假定存在冲突。首先使用一个锁定,处理事务,然后释放锁定。   图6-10和图6-11显示了使用这两种方式处理同一个示例的情况。在这个示例中,事务将PRODUCT表中铅笔行的数量减少5。图6-10显示了乐观锁定的情况。首先读取数据,并且将铅笔的Quantity当前值存入OldQuantity变量。然后处理事务,假设所有这些操作都得以顺利实现,则PRODUCT就得到一个锁。这个锁可能只对铅笔行起作用,或者可作用于更高的粒度级别。无论何种情况,都将执行一条更新铅笔行的SQL语句,其中的WHERE条件指定Quantity的当前值等于OldQuantity值。如果没有其他的事务修改铅笔行的Quantity值,那么这个UPDATE语句就可成功执行。如果有另一个事务修改了铅笔行的Quantity值,则UPDATE操作将会失败,需要重新执行事务。 图6-10 乐观锁定示例         图6-11描述了对相同事务采用悲观锁定的逻辑。在这种情况下,在所有操作开始运行前,PRODUCT(在某个粒度级别上)得到一个锁定。然后读取数值,处理事务,执行UPDATE语句,最后再解除对PRODUCT的锁定。   乐观锁定的优点是当事务处理完后才获取锁定。因此,锁定的持续时间比悲观锁定更短。如果事务复杂或客户机的速度较慢(因为传输延迟或用户在执行其他工作、用户休息或者没有退出应用程序就关机等),锁定持续的时间就会相对少很多。如果锁定粒度大(如整个PRODUCT表),这个优点就显得更为重要。 图6-11 悲观锁定的示例   乐观锁定的缺点是,如果针对铅笔行同时有很多操作,事务就可能必须重复执行很多次。因此,如果事务需要对指定行执行很多操作(比如购买一种热门股票),就不适合使用乐观锁定。 6.2.9 声明锁定特征   并发控制是一个复杂的问题;一些锁定的类型和策略必须经过反复试验和纠正之后才能决定。因为这个以及其他原因,数据库应用程序一般不显式地使用锁定。相反,程序标记事务边界,然后声明它们希望DBMS使用的锁定行为的类型。通过这种方法,如果需要改变锁定行为,就不需要重新编写应用程序来锁定事务的不同区域,而只需修改锁定声明。   图6-12描述了一个铅笔事务,以BEGIN TRANSACTION、COMMIT TRANSATION和ROLLBACK TRANSACTION等语句标记事务的边界。这些边界提供了DBMS执行不同锁定策略所需的基本信息。如果现在开发人员声明(通过系统参数或类似途径)需要乐观锁定,那么DBMS将隐式地在适当的位置上设置锁定类型。如果后来希望改为悲观锁定,那么DBMS会隐式地将悲观锁定设置在另一个位置。 图6-12 标记事务边界的示例 6.2.10 一致事务   有时候,会看到首字母缩略词ACID运用到事务上。所谓ACID事务是一种原子性的(atomic)、一致的(consistent)、隔离的(isolated)和持久的(durable)事务。原子性和持久性都容易定义。原子事务是指或者执行事务中所有的数据库操作,或者不执行其中任何一个操作。持久性事务是指事务中所有提交的修改都是永久的。DBMS不会取消这些修改,即使在发生错误时也是如此。如果事务是持久的,那么DBMS将在需要时提供辅助措施来恢复在所有提交操作中进行的修改。   术语一致性和隔离性不像原子性和持久性那样容易定义。请考虑以下的SQL更新命令: UPDATE CUSTOMER SET AreaCode = '425' WHERE ZipCode ='98050'   假设在CUSTOMER表中有500000行,其中有500行的ZipCode值均为98050。那么DBMS需要花费一些时间才能找到这所有的500行。在这段时间内,允许其他事务更新CUSTOMER的AreaCode或ZipCode字段吗?如果SQL语句是一致的,这样的更新就是不允许的。如果在SQL语句执行时找到了匹配行,则将对这些行集进行更新。这种一致性称为语句级一致性(statement level consistency)。   现在考虑包含两个SQL更新语句的事务: BEGIN TRANSACTION UPDATE CUSTOMER SET AreaCode='425' WHERE ZipCode='98050' . . . {other transaction work} . . . UPDATE CUSTOMER SET Discount=0.05 WHERE AreaCode='425' . . . {other transaction work} . . . COMMIT TRANSACTION   在这个上下文中,“一致性”又表示何种意义呢?语句级一致性表示不同的语句将独立处理一致的数据行,但是在这两个SQL语句执行的间隔中,允许其他用户对这些数据行进行修改。事务级一致性(transaction level consistency)意味着,两个SQL语句作用到的所有数据行在整个事务运行期间都受到保护。   然而,也可以发现,在实现事务级一致性时,事务本身并不能发现自身的变化。在上面的示例中,第二个SQL语句并不知道有些数据行已经被第一个SQL语句改变。   因此,当听到“一致性”这个术语时,需要进一步确定它属于哪种一致性。此外,也需要小心处理事务级一致性的潜在问题。隔离(isolated)的情况更为复杂,我们将在接下来的章节中讲解。 6.2.11 事务隔离级别   1992年,ANSI SQL标准定义了4个事务隔离级别(isolation level),这种隔离标准指定了允许产生哪种并发控制问题。图6-13展示了这4个隔离级别。 隔 离 级 别 读取未提交 读取已提交 可重复读取 可串行化 问题 类型 脏读取 可能 不可能 不可能 不可能 不可重复读取 可能 可能 不可能 不可能 幻象读取 可能 可能 可能 不可能 图6-13 隔离级别汇总   使用这4个隔离级别的目的是让应用程序编程人员能够声明将使用的事务隔离级别,然后由DBMS通过管理锁定来实现相应的事务隔离级别。如图6-13所示,“读取未提交”隔离级别允许“脏读取”、“不可重复读取”和“幻象读取”。在“读取已提交”隔离级别中,不允许“脏读取”。在“可重复读取”隔离级中,禁止“脏读取”和“不可重复读取”。而在“可串行化”隔离级别中,禁止上面的3种操作。   虽然吞吐量也和工作负荷以及应用程序的编写方式息息相关,但从总体来说,隔离级别越高,吞吐量越小。而且,不是所有的DBMS产品都会同时支持这4种隔离级别,产品对它们的支持方式和对应用程序开发人员的要求也各有不同。 6.3 游标类型   游标(cursor)是一种指针,指向从SQL SELECT语句得到的结果行集,它常常通过SELECT语句来定义。比如,下面的语句定义了一个名为TransCursor的游标,该游标的操作对象是由SELECT语句指定的行集: DECLARE CURSOR TransCursor AS       SELECT *       FROM [TRANSACTION]       WHERE PurchasePrice > '10000';   在应用程序打开某个游标后,该程序可以把该游标放到结果集中的某个地方。最常见的情况是,把游标放到第一行或最后一行,但是也可能放在其他地方。   一个事务可以打开多个游标——可以依次打开,也可以同时打开。此外,可能打开同一个表的两个或多个游标;可能直接打开关于该表的游标,也可能是通过关于该表的SQL视图来打开。由于游标需要相当大的内存,因此同时打开很多游标(比如,为一千个当前事务打开游标)将消耗大量的内存。减少游标所带来负担的一个方法是定义缩容(reduced-capability)游标,并在不需要满容量游标的时候使用它们。   图6-14给出了Windows环境中所使用的4种游标类型(其他系统中的游标类型也与此类似)。最简单的游标是“只向前游标(forward only cursor)”。通过该游标,应用程序只能向记录前面执行。对于由事务中其他游标或其他事务所做的修改,只有当它们发生在游标所在行之前才是可见的。   另外3种游标类型又被称为“可滚动游标(scrollable cursor)”,因为应用程序可以向记录前面或后面滚动。静态游标(static cursor)快速绘制并处理关系的图,使用这种游标进行的修改是可见的,而来自其他源的修改都是不可见的。   动态游标(dynamic cursor)是一种很有特色的游标。对于动态游标而言,所有以行的顺序进行的插入、更新、删除和修改都是可见的。除非事务的隔离级别是脏读取,否则只有提交的修改才是可见的。   键集游标(keyset cursor)结合了静态游标和动态游标的一些特点。打开该游标后,将保存每一行的主键的值。当应用程序把游标放在行中时,DBMS使用该键值来读取行的当前值。由本事务或其他事务中的其他游标所插入的新行是不可见的。如果应用程序发出一个对行的更新命令而该行已经被其他游标删掉了,那么DBMS将创建一个新行,该行保持旧的键值,并把更新的数值插入到新行中(假设所有必需的字段都存在)。对于动态游标而言,除非事务的隔离级别是脏读取,否则只有已提交的更新和删除对于游标来说是可见的。   对于每种类型的游标来说,支持游标所需的系统开销和处理的数量也不相同。一般来说,开销随着类型的下降(如图6-14所示)而增加。因此,为了提高DBMS的性能,应用程序开发人员应该创建足以完成工作的游标即可。同时,了解特定的DBMS如何实现游标以及游标是否位于服务器或客户机上也是非常重要的。有些情况下,把动态游标放到客户机上可能比把静态游标放到服务器上要更好。因为性能取决于DBMS产品以及应用程序需求所使用的实现方式,所以并没有规定一般规则。 游 标 类 型 说 明 注 释 只向前游标 应用程序只能向记录前面移动 对于由事务中其他游标或其他事务所做的修改,只有当它们发生在游标所在行的前面时才是可见的 静态游标 应用程序在打开游标时才可以看到数据 由静态游标所做的修改是可见的。来自其他源的修改是不可见的。允许向前和向后的滚动 键集游标 当打开键集游标时,每行的主键都保存到了记录集中。当应用程序访问行时,该键用来取回该行的当前值 来自任何源的更新都是可见的。来自键集游标外部的源的插入是不可见的(因为在键集中没有这些源的键)。来自键集游标的插入显示在该记录集的底部。来自任何源的删除都是可见的。而以行的顺序排列的修改都是不可见的。如果隔离级别是脏读取,那么提交的更新和删除都是可见的;否则只有提交的更新和删除才是可见的 动态游标 任何类型的修改以及来自任何源的修改都是可见的 所有按记录集顺序进行的插入、更新、删除和修改操作都是可见的。如果隔离级别是脏读取,那么未提交的修改是可见的。否则,只有提交的修改才是可见的 图6-14 游标类型的汇总   需要小心的是:如果没有指定事务的隔离级别或没有指定被打开游标的类型,那么那么DBMS将使用默认的级别和类型。这些默认的级别和类型对于您的应用程序来说可能非常适合,但是它们也可能成为麻烦。因此,即使可以不考虑这些问题,但是这些问题所带来的后果也是无法回避的。所以必须搞懂DBMS产品的功能。 6.4 数据库安全   数据库安全的目的就是确保只有授权用户才可以在授权时间内进行授权的操作。这一目标通常分为两个部分:身份验证(即确保用户拥有首先使用该系统的基本权限)和授权(即授予用户对系统进行特定操作的具体权限和许可)。如图6-15所示,用户验证要求用户通过密码(或其他明确的身份证明,如手指纹的生物仪器扫描等)登录到系统中,而用户授权则是通过授予用户DBMS特定的许可而达到的。 图6-15 数据库安全的身份验证与授权   注意,仅仅通过身份验证(用户登录到系统中)对于数据库的使用来说还是不够的——除非用户还获得了相应的许可,否则他(或她)就不可以访问数据库或执行使用数据库的操作。   因此,实现数据库安全的目标很难,但是无论执行哪些改进,数据库开发小组都必须确定(1)哪些用户可以使用数据库(即进行身份验证);(2)每个用户的处理权限和责任。这些安全需求可以通过DBMS的安全特性以及写入应用程序的附加安全特性来实现。 6.4.1 用户账户   比如,考虑示例Heather Sweeney Designs公司的数据库安全需求。必须采取措施来控制访问数据库的员工。其中一个方法是为每个员工创建用户账户。图6-16展示了SQL Server 2005中在DBMS安全级别上创建用户登录HSD-User的情况。 图6-16 数据库服务器登录的创建   该步骤所创建的是DBMS(而不是特定的数据库)中最初的用户账户,相应赋予的密码是HSD-User+password,在第7章HSD Web页面中也需要这一密码。注意,在Windows环境中,控制身份验证的方法有两种:第一种,使用Windows操作系统来控制身份验证;第二种,通过账户的登录名和密码来创建SQL Server内部用户账户。对于其他DBMS产品而言,如果没有像SQL Server一样被操作系统指定,那么只能使用第二种方法,即使用内部用户账户。   应该小心管理用户账户和密码。DBMS账户和密码安全的正确术语、特性和功能取决于所使用的DBMS产品。 6.4.2 处理权限和责任   所有主流的DBMS产品都提供了限制特定客户对特定对象进行特定操作的工具。DBMS安全的一般模型如图6-17所示。 图6-17 DBMS安全模型   根据图6-17所示,可以赋予用户一个或多个角色(组),一个角色可以拥有一个或多个用户。用户、角色和对象(使用的是其通用的含义)拥有许多许可。每个许可然后被赋予一个用户或角色以及一个对象。一旦用户通过了DBMS的身份验证,DBMS将把该人的行为限制在用户确定的许可范围内,或限制在用户所赋予的角色的许可范围内。   现在,考虑Heather Sweeney Designs公司的用户身份验证问题。该公司存在3类用户:administrative assistant(行政助理),management(经理,即Heather),systems administrator(系统管理员,即Heather的顾问)。图6-18是Heather根据她的业务需要确定的处理权限。   行政助理可以读取、插入和修改所有表中的数据,但是只可以删除SEMINAR_CUSTOMER和LINE_ITEM中的数据。这就意味着,他们有权利从培训课中删除客户,并可以从订单中删除产品项。经理除了不能删除CUSTOMER数据外,可以对所有的表执行所有操作。这里Heather考虑到,鉴于赢得客户的不易,她不愿因为不小心删除了CUSTOMER数据而失去客户。   最后,系统管理员可以修改数据库的结构,对其他用户进行授权(授予权限),但不能对数据进行操作。系统管理员不是用户,因此不允许其访问用户数据。这一限制似乎很有限。毕竟,如果系统管理员可以指定权限,他(或者她)可以通过改变权限来绕开安全系统,从而可以进行所需要的任何操作,修改数据,然后将权限再修改回去。这些情况都有可能发生,但是会在DBMS日志中留下审计跟踪。这些以及对安全系统进行改变的需求可以阻止系统管理员进行未授权的活动。这明显优于允许系统管理员具有无效的用户数据访问权限。 授予的数据库权限 表 行 政 助 理 经 理 系统管理员 SEMINAR 读取 插入 修改 读取 插入 修改 删除 授予权限,修改结构 CUSTOMER 读取 插入 修改 读取 插入 修改 授予权限,修改结构 SEMINAR_CUSTOMER 读取 插入 修改 删除 读取 插入 修改 删除 授予权限,修改结构 CONTACT 读取 插入 修改 读取 插入 修改 删除 授予权限,修改结构 INVOICE 读取 插入 修改 读取 插入 修改 删除 授予权限,修改结构 LINE_ITEM 读取 插入 修改 删除 读取 插入 修改 删除 授予权限,修改结构 PRODUCT 读取 插入 读取 插入 修改 删除 授予权限,修改结构 图6-18 Heather Sweeneys Designs公司的处理权限   数据库安全管理(以及网络管理)的一个非常重要的规则是:除非绝对需要,否则图6-18中所给出的权限类型是授予用户组(也称之为用户角色)的,而不是个人的。当然,可能会存在需要赋予特定用户对数据库权限的情况,但是应尽可能避免这些情况的出现。同时也要注意到,在使用组或角色时,需要通过某种方法将用户划分到一定的组中。当Heather Sweeney登录到计算机时,就需要通过一些方法来确定她所属的组。   接下来考虑如何在HSD数据库中赋予角色和权限。HSD-User是Heather的一名行政助理,因此她(或他)需要具备读取、插入和修改所有表中数据的能力。首先,需要授予HSD-User权限以便其可以在DBMS中使用HSD数据库。图6-19给出了在SQL Server 2005中HSD数据库安全级别上创建数据库级别的用户(名为HSD Database User)的方法。注意,该用户是专门为HSD数据库创建的,但是它是建立在已经创建的DBMS登录名的基础上的。同时还应注意到在SQL Server 2005中,密码并不是在数据库安全级别上赋予的,而是只在DBMS安全级别上进行设定的。 图6-19 数据库用户名称的创建   图6-20汇总了SQL Server 2005中固定的一些数据库角色及其相关的权限。因为HSD Database User需要读取、插入或修改HSD数据库中所有表中数据的能力,因此将赋予HSD Database User两个角色:db_datareader和db_datawriter。图6-21展示了向HSD Database User添加db_datawriter角色的情况。       固定的数据库角色 数据库的具体权限 DBMS服务器的权限 db_accessadmin 授予的权限:ALTER ANY USER,CREATE SCHEMA; 使用GRANT选项授予的权限:CONNECT 授予的权限:VIEW ANY DATABASE db_backupoperator 授予的权限:BACKUP DATABASE,BACKUP LOG,CHECKPOINT 授予的权限:VIEW ANY DATABASE db_datareader 授予的权限:SELECT 授予的权限:VIEW ANY DATABASE db_datawriter 授予的权限:DELETE、INSERT和UPDATE 授予的权限:VIEW ANY DATABASE db_ddladmin 授予的权限:参见SQL Server 2005相应的文档 授予的权限:VIEW ANY DATABASE db_denydatareader 取消的权限:SELECT 授予的权限:VIEW ANY DATABASE db_denydatawriter 取消的权限:DELETE、INSERT和 UPDATE 授予的权限:VIEW ANY DATABASE db_owner 通过GRANT选项授予的权限:CONTROL 授予的权限:VIEW ANY DATABASE db_securityadmin 授予的权限:ALTER ANY APPLICATION ROLE,ALTER ANY ROLE,CREATE SCHEMA,VIEW DEFINITION 授予的权限:VIEW ANY DATABASE 图6-20 SQL Server 2005中固定的一些数据库角色 图6-21 赋予HSD Database User角色db_datawriter   我们将在下一节中进一步讨论这个问题。   在该讨论中,我们提到了处理权限和责任。从字面上可以看出,权限和责任是互相依存的。举例来说,当系统管理员删除了CUSTOMER中的数据时,她就有责任确保她所删除的数据不会对公司的运作、财务等产生负面影响。   处理责任无法由DBMS或者应用程序强加于用户。事实上,责任会写进用户手册,并且通过系统培训传达给用户。这些是系统开发手册的内容。在这里,我们不再作进一步的讨论,但是需要反复强调,权利与责任同在,责任必须明文规定,并且需要强制实施。   DBA也需要管理权利和责任。也就是说,责任和权利会随着时间变化而变化。使用数据库并且根据应用程序和DBMS的结构调整而进行改动时,就会相应地需要新的或不同于以前的权利和责任。DBA是研究和实现权利和责任变化的关键。   一旦定义了处理权限,就可以在很多级别上实现它们:操作系统、网络目录服务、Web服务器、DBMS和应用程序。在下面的两节中,我们将讨论处理权限在DBMS和应用程序中的实现,其他的实现不在本书讨论范围之内。 6.4.3 DBMS级别的安全   图6-22列出了DBMS的安全指南。首先,DBMS必须在防火墙后运行。在绝大多数情况下,不允许从企业网络的外部初始化任何与DBMS或数据库应用程序之间的通信。但是,如果DBMS支持电子商务应用程序,那么可以不遵循这一规则。在这种情况下,DBMS就应该只支持电子商务应用程序。所有其他的数据库应用程序应该由防火墙后不同机器上的不同DBMS进行管理。 图6-22 DBMS安全指南   其次,必须尽可能应用操作系统和DBMS的最新服务包和补丁。在2003年春季,“监狱”蠕虫病毒利用了SQL Server中的安全漏洞,从而使许多大型企业的数据库应用程序陷于瘫痪。在此之前,Microsoft已经发布了消除这一漏洞的补丁。因此,所有安装了该补丁的企业都没有遭受到该蠕虫病毒的影响。   第三种保护是将DBMS的功能限制为只有应用程序需要的特性和功能。例如,Oracle可以支持多种不同的通信协议。为了提高安全性,任何Oracle支持但却没有使用的协议就应该被删除或被禁止。同样,每个DBMS中都会有上百个系统存储的过程,任何一个不使用的过程都应该从操作的数据库中删除。   另一个重要的安全措施是保护运行DBMS的计算机。禁止任何用户在DBMS计算机上工作,并且这个计算机应该放置于上锁的单独房间里。对放有DBMS房间的访问应该有相应的日期和时间记录。   用户可以自己输入用户名和密码,而在有些应用程序中,输入的用户名和密码将会代表用户本身。比如,如图6-16所示,Windows XP操作系统中的用户名和密码可以直接传递给SQL Server。另外一些情况下,应用程序则会提供用户名和密码。   Internet应用程序通常会定义一个如Unknown Public这样的用户组,并在匿名用户登录时将其分配到这个组中。通过这种方式,与未知客户进行电子商务的公司就不需要将每一位未知客户的用户名和密码输入到它们的安全系统中。   SQL Server、MySQL、Oracle和DB2使用的安全系统和图6-17中所示的模型不尽相同,所用的术语也可能不同,但它们的安全系统在本质上是相同的。 6.4.4 应用程序级别的安全   虽然诸如SQL Server、MySQL、Oracle和DB2这样的DBMS产品确实提供了具体的数据库安全特性,但是这些特性本质上都只实现了常规性的安全保护。如果应用程序要求特别的安全措施,例如,禁止用户查看某个表的行,或者禁止查看表连接中其他雇员的数据行,此时DBMS的安全机制就无能为力了。在这些情况下,必须通过数据库应用程序的特性来提高系统的安全性。   举例来说,Internet应用程序的安全通常由Web服务器提供。在这个服务器上执行应用程序安全措施意味着敏感的安全数据不必通过网络进行传输。   为了更好地理解这一点,假定应用程序采用如下设计方案:当用户单击浏览器页面上的某个特定按钮后,将向Web服务器发送下面的查询,然后再将其发送给DBMS。 SELECT * FROM EMPLOYEE;   这个语句将返回所有的EMPLOYEE行。如果应用程序安全机制只允许员工访问他们自己的数据,那么Web服务器可以将如下WHERE子句添加到该查询中: SELECT * FROM EMPLOYEE WHERE EMPLOYEE.Name = '<%SESSION("EmployeeName")%>';   如同您在学习Internet应用技术时所了解到的那样,上面的表达式将让Web服务器把员工的名字代入WHERE语句中。对于以Benjamin Franklin身份登录的用户,上面的表达式就会变成如下形式: SELECT * FROM EMPLOYEE WHERE EMPLOYEE.Name ="Benjamin Franklin";   因为这个名字是由Web服务器上的程序插入的,浏览器用户并不知道发生了什么,所以不能加以干涉。如上文所示,可以在Web服务器上完成这样的安全处理,但也可以在应用程序本身内部实现,或者编写成可以在适当时由DBMS执行的存储在DBMS中的代码。   进一步扩展这种思想:在Web服务器可访问的安全数据库中存储附加数据,以及使用存储DBMS代码。举例来说,安全数据库可以包含与WHERE子句的附加值匹配的用户身份。例如,假设人事部的用户可以访问自身以外其他用户的数据。可以将合适的WHERE子句存储到安全数据库中,应用程序读取这些信息,并且根据需要将其添加到SQL SELECT语句中。   通过应用程序处理扩展DBMS安全还有很多其他的方法,但是总体而言,应该先利用DBMS本身的安全特性。只有当它们不能满足要求时,您才需要添加应用程序代码。安全措施和数据的关系越紧密,泄密的可能性就越小。同时,使用DBMS安全特性比自己编写代码更快速,代价更小,而且效果可能更好。 6.5 数据库备份与恢复   计算机系统崩溃、硬件损坏、程序故障、编写程序中的错误以及人为错误,所有这些都会出现在数据库应用程序中。因为数据库是很多用户共享的,并且常常是一个组织运作的关键因素,所以出现问题后,尽快恢复数据库显得尤为重要。   为此,必须解决几个问题。首先,从业务角度来说,必须维持业务功能。例如,客户需要手工完成订单、金融交易以及装箱清单。之后,当数据库应用程序在后面恢复使用时,可以输入新的数据。其次,计算机操作人员必须尽快将系统恢复到可用状态,并且与崩溃前的系统尽可能接近。再次,用户需要知道系统恢复后应该怎样做。如果需要重新输入数据,用户就必须知道需要重新输入多少数据。   出现故障后,不仅仅是简单地解决问题并继续操作。即使在故障中没有丢失数据(假定所有的存储类型都是永久性的——这是一个不现实的假设),计算机处理的计时和进度也会因为太复杂而无法精确地重新创建。操作系统需要大量的额外数据和处理才能精确地从中断处重新处理。无法简单地使时间倒退,也不能使所有的数据恢复到和出现故障时相同的状态。然而,有两种可能的方法:即通过重新处理进行恢复和通过回滚/前滚进行恢复。 6.5.1 通过重新处理进行恢复   因为不能精确地从某一处恢复处理,所以最好的替代方法就是回溯到已知状态并重新处理当时的所有工作。这种恢复的最简单形式包括周期性地复制数据库(称为数据库备份),并且记录下自该备份后处理的所有事务。在故障发生之后,操作人员可以恢复保存过的数据库,并重新处理所有事务。   遗憾的是,这种简单的应对措施一般并不可行。首先,重新处理事务需要耗费和第一次处理时相同的时间。如果计算机的任务过多,那么系统可能不堪重任。其次,即使可以并发处理事务,但事务却是异步的。用户操作上的细微变化(比如用户在应该响应应用程序提示前读取电子邮件消息),这时就可能改变并发事务的执行顺序。结果,在原来的处理中,本来应该是Customer A得到航班的最后一个座位,而在重新处理时,却变成了Customer B获得了最后一个座位。由于上面的原因,重新处理通常并不是多用户系统中产生故障时可靠的恢复方法。 6.5.2 通过回滚和前滚进行恢复   第二种方法需要定期备份数据库,并且记录下自保存备份后事务对数据库所做的改动。然后,在故障发生后,可以使用两种方法中的一种。第一种方法称为前滚(rollforward):通过已保存的数据库文件恢复数据库,并且重新应用保存后的所有有效事务。注意,这种方法并不需要重新处理事务,这是因为前滚并不涉及应用程序。相反,它只是重新应用日志中记录已处理的改动。   另外一种方法称为回滚(rollback),在这种方法中,可以取消错误地执行或者没有全部完成的事务对数据库的更改,以此来纠正错误。这样就可以重新启动发生故障时正在进行的有效事务。   如上所述,这两种方法都需要通过日志保存事务结果。日志按照时间顺序记录数据的变化。注意,在把事务应用到数据库之前,必须将它们写入日志。通过这种方式,如果系统在记录事务和应用到数据库之间崩溃,那么最多只有一个未应用事务的记录。而如果事务在记入日志前就已经应用到数据库中,那么就有可能出现数据库已经被改变而没有相应记录的情况(我们并不期望出现这种情况)。如果发生了这种情况,不知情的用户就会重新执行已经执行过的事务。   如图6-23所示,故障发生时,我们使用日志来撤销和恢复事务。如图6-23(a)所示,为了撤销事务,日志必须包含数据库发生变化前的所有记录的副本。这些记录称为前像(before-images)。可以通过将所有改动的前像应用到数据库中来撤销事务。 (a)回滚 (b)前滚 图6-23 撤销和恢复事务   如图6-23(b)所示,为了恢复事务,日志中必须包含数据库改变之后的所有记录(或页面)的副本。这些记录称为后像(after-images)。通过将所有改动的后像应用到数据库来恢复事务。图6-24展示了事务日志中可能记录的数据项。   在这个日志示例中,为了便于标识,每个事务都有唯一的名称。然后,每个给定事务的所有映像都通过游标链接在一起。一个游标指向由该事务改动前的映像(反向游标),另外一个游标指向该事务改动后的映像(前向游标)。如果游标字段为空,则表明此处到达列表的尾端。DBMS恢复子系统通过这些游标来查找特定事务的所有记录。图6-24为事务日志记录的链接示例。 相对记录号 事务ID 反向游标 前向游标 时间 操作类型 对象 前像 后像 1 OT1 0 2 11:42 START CUST 100 (旧值) (新值) 2 OT1 1 4 11:43 MODIFY 3 OT2 0 8 11:46 START SP AA (旧值) (新值) 4 OT1 2 5 11:47 MODIFY ORDER 11 (值) 5 OT1 4 7 11:47 INSERT 6 CT1 0 9 11:48 START 7 OT1 5 0 11:49 COMMIT 8 OT2 3 0 11:50 COMMIT 9 CT1 6 10 11:51 MODIFY SP BB (旧值) (新值) 10 CT1 9 0 11:51 COMMIT 图6-24 事务日志示例   日志中还可能包括其他数据项:(1)操作时间;(2)操作类型;(3)作用对象(如记录类型和标识符);(4)后像和前像。对于包含后像和前像的日志,执行重做操作和撤销操作都很方便。注意,START表示开始事务,COMMIT表明终止事务,并释放所有的锁定。   如果日志中含有了前像和后像,那么撤销和恢复工作就很简单明了。图6-25显示了如何从系统中恢复的情况。   为了撤销图6-25(a)中的事务,恢复处理器仅仅需要用前像替换改变了的记录即可(如图6-25(b)所示)。当所有的前像都恢复之后,事务也撤销了。为了重做某个事务,恢复处理器可以运行这个事务开始之前的数据库版本并应用所有的后像。这一步骤的前提是,假定可以从保存的数据库备份中获得数据库的早期版本。      将数据库恢复到最近的一次备份并且重新应用所有的事务,这可能需要进行很多的处理。为了减少延迟,DBMS产品有时会用使用检查点(checkpoint)。检查点是数据库和事务日志之间的同步点。为了执行检查点,DBMS拒绝新的请求,结束处理未完成的请求,并将缓存写入磁盘。然后,DBMS会一直等待操作系统发出通知,告知数据库所有的主要请求已经成功写入数据库和日志。此时,日志和数据库同步。然后,检查点也被记录到日志中。恢复数据库时,只需要从检查点处开始即可,而且只需应用检查点后开始的事务后像。 (a)处理错误 (b)恢复处理 图6-25 恢复策略的示例   记录检查点并不费事,可以在1小时内记录3个到4个(或者更多)检查点。通过这种方法,最多只需要恢复15~20分钟的处理。大多数DBMS产品会自动记录检查点,不需要人工干预。   如果使用SQL Server、MySQL、Oracle或DB2之类的产品进行数据库管理工作,那么您还需要进一步地学习有关备份和恢复的知识和技术。就本书而言,只需要了解一些基本思想,并且知道制定充足的备份和恢复计划、保存必需的数据库备份和日志是DBA的责任。 6.5.3 DBA的其他职责   并发控制、安全和可靠性是数据库管理的3个重点。但是,DBA的其他管理功能同样也非常重要。   举例来说,DBA需要确保采用一个系统来收集和记录用户报告的错误以及其他的问题。需要对这些问题进行优先级排序,以便确保它们能相应地得到解决。从这一点看来,DBA需要和开发团队协作,不仅需要解决已经存在的问题,还要评估新版本DBMS的特性和功能。   在使用数据库的过程中,会出现一些新的要求并需要加以实现,这时也就要求对数据库的结构进行一些调整。对已经投入运行的数据库结构进行调整需要格外小心,并且需要详尽的计划。因为数据库是共享资源,一个用户或团体期望的结构更改却很可能给其他的用户和团体带来灾难。   因此,DBA需要创建并管理一个控制数据库配置的进程。这样的进程包括以下一些过程:记录修改请求、构造用户和开发人员浏览该请求的汇总、创建用来实现批准改动的项目和任务。所有这些操作都需要经过统筹安排。   最后,DBA还负责正确维护文档,从而记录数据库结构、并发控制、安全、备份、恢复、应用程序的使用,以及大量与数据库的管理和使用相关的细节。一些供应商提供了记录这些文档的工具。DBMS最低限度需要提供用来处理数据库的DBMS自身的元数据。一些数据库产品采用某些辅助程序扩充了元数据,用来存储并报告操作过程和应用程序元数据。   DBA在处理和管理数据库中责任重大。具体的责任会因数据库的类型和规模、用户人数、应用程序的复杂程度而有所不同。但是,对任何一个数据库来说,这些责任都非常重要。即使您使用的是非常小的个人数据库,仍然需要充分意识到DBA服务的必要性,并思考本章提及的各个内容。   在结束本章之前,下面将介绍两种先进的数据库——分布式数据库和对象-关系数据库。 6.6 分布式数据库的处理   分布式数据库就是在多台计算机上进行存储和处理的数据库。根据不同的数据库类型和所允许的处理,分布式数据库可以显示重要的问题。下面先考虑分布式数据库的类型。 6.6.1 分布式数据库的类型   可以通过分区(partitioning)来分布数据库,也就是将数据库分割为不同的片段并将这些片段存储在多台计算机中;也可以通过复制(replication)来分布数据库,也就是将数据库的副本存储在多台计算机中;或者通过分区和复制的联合。   图6-26图示了这些方法。图6-26(a)显示了一个非分布式数据库,其中包含4个部分,分别标记为W、X、Y和Z。在图6-26(b)中,数据库已经分区,但没有被复制。在计算机1中存储和处理W和X部分,在计算机2中存储和处理Y和Z部分。图6-26 (c)显示了已经复制但没有分区的数据库。在计算机1和计算机2中存储和处理整个数据库。最后,图6-26(d)显示了同时进行分区和复制的数据库。在计算机1和计算机2中存储和处理数据库的Y部分。   可以通过多种方式定义分区或复制的部分。如果有一个包含5张表的数据库(例如CUSTOMER、SALESPERSON、INVOICE、LINE_ITEM和PART),则可以按如下方式对其进行分区:将CUSTOMER赋给W部分,将SALESPERSON赋给X部分,将INVOICE和LINE_ITEM赋给Y部分,将PART赋给Z部分。另外,每个表的不同行都可以赋给不同的计算机,或者每个表的不同列都可以赋给不同的计算机。   对数据库进行分布主要有两个原因:性能和控制。在多台计算机上放置数据库可以提高吞吐量,这是因为多台计算机可以共享工作量,或者是因为缩短用户和计算机的距离可以减少通信延迟。数据库分布可以通过将数据库的不同部分分离到不同计算机上来改进控制能力,这些不同部分都有自己的授权用户集和权限。 图6-26 分布式数据库的类型 6.6.2 分布式数据库面临的挑战   在分布数据库时,必须克服所遇到的挑战。这些挑战取决于分布式数据库的类型和所允许的操作。在完全复制的数据库中,如果只允许一台计算机对一份副本进行更新,则此时的挑战并不大。所有的更新操作都发生在一台计算机上,并且数据库的副本会周期性地发送到复制地点。此时面临的挑战就是确保只有一个逻辑上一致的数据库副本被分布(比如,没有局部的或未提交的事务),并且保证该地点可以理解所处理的数据也许不是最新的,因为在建立本地副本后,可能已经对更新数据库进行了这种改变。   如果多台计算机对复制数据库进行更新,那么就会出现难题。特别地,如果允许两台计算机在同一时间对同一行进行处理,则会造成3种类型的错误:它们会带来不一致的更新;一台计算机删除一行的同时,另外一台计算机正在对该行进行更新;或者两台计算机的更新违反了唯一性约束。   为了阻止这些问题的发生,就需要锁定一些类型的记录。由于涉及到多台计算机,标准记录锁定将不起作用。相反,必须使用一种更为复杂的锁定方案,称为分布式两段锁定(distributed two-phase locking)。这种方案的细节不在本书的讨论范围之内。但是,实现这一算法非常困难,而且代价很高。到目前为止,您只需要认识到,如果多台计算机可以处理分布式数据库的多个复制,则必须解决这些重要的问题。   如果对数据库进行分区,但没有进行复制(见图6-26 (b)),则跨越两个或更多分区进行事务更新就可能出现问题。假设CUSTOMER和SALESPERSON表位于一台计算机上,INVOICE、LINE_ITEM和PART表位于另外一台计算机上。再进一步假设记录一次交易时,需要在一次原子事务中更新所有5个表。在这种情况下,两台计算机必须同时开始这一事务,只有在两台计算机都同意提交更新的情况下才能在其中一台计算机上提交更新。此时必须使用分布式两段锁定。   如果以如下方式分区数据:没有任何一个事务向两个分区请求数据,此时常规锁定就会起作用。但是,在这种情况下,数据库实际上是两个独立的数据库,有些人因此认为,不应该将它们看作是分布式数据库。   如果以如下方式分区数据:没有一个事务更新两个分区中的数据,但有一个或多个事务从一个分区中读取数据,并且更新另一个分区的数据。那么常规锁定无法确定是否会出现问题。如果存在脏读取,则需要一些形式的分布式锁定;否则,常规锁定应该起作用。   如果分区数据库,并且至少复制一个分区,则锁定需求就是上面两种情况的结合。如果更新了复制部分并且事务跨越了不同的分区,或者如果存在脏读取,则需要分布式两段锁定。否则,常规锁定应该起作用。   分布式处理是复杂的过程,并且会出现实际问题。除了复制的只读数据库,只有投资实际预算和时间充裕的有经验团队才应该尝试使用分布式数据库。使用这一类数据库也要求具备数据通信方面的专业知识。因此,分布式数据库不适合于实力较差的公司。 6.7 对象-关系数据库   面向对象的编程(OOP)是设计和编写计算机程序的技术。现在,几乎所有的程序开发都使用OOP技术。Java、C++、C#和Visual Basic .NET都是面向对象的计算机程序。   对象含有方法(即执行任务的计算机程序)和属性(该对象特有的数据项)。给定类的所有对象都有相同的方法,但每一个对象都有属于自己的数据项集。使用OOP时,创建对象的属性并存储在主内存中。存储对象的属性值称为对象持久化(object persistence)。可以使用多种技术实现对象持久化,其中的一种就是使用多种数据库技术。   虽然关系数据库可以用于对象持久化,但做到这一点需要程序员进行大量的实际工作。问题在于,一般情况下,对象数据结构比表的行更为复杂。特别是不同表的一些乃至更多的行需要用于存储对象数据。这就意味着,OOP的程序员必须专门设计小型数据库来存储对象。在信息系统中需要使用许多对象,因此需要设计并处理多个不同的小型数据库。这种方法的前景并不能满足多种需要,因此很少用到它。   在20世纪90年代初期,一些软件供应商开发了专门用于存储对象数据的DBMS产品。这些称为面向对象DBMS(OODBMS)的产品从来没有获得过商业成功。问题在于,引入这些产品之前,已经以关系DBMS的格式存储了无数的数据。没有一个组织愿意为了使用OODBMS而将数据转换为OODBMS格式。因此,这类产品在市场上都没有获得成功。   但是,关于对象持久化的需求从没有停止过。一些供应商(以Oracle为代表)在其关系数据库DBMS产品上添加了一些特性和功能。这些特性和功能基本上是关系数据库的增件,它们有利于对象的持久化。相比于使用纯粹的关系数据库,使用这些产品可以更容易地存储对象数据。然而,对象关系数据库仍然可以同时处理关系数据。   如果您希望学习关于对象关系数据库的更多知识,可以访问Oracle的Web站点:www.Oracle.com。也可以在Web上搜索OODBMS和ODBMS。 6.8 Access工作台:第六部分——Microsoft Access中的数据库管理   至此,我们已经创建并填充了Wallingford Motors CRM数据库中的CONTACT表、CUSTOMER表、SALESPERSON表和VIHICLE表。同时,在前面的章节中我们还学习了如何创建表单、报表和查询,在附录C中还学习了如何创建和使用视图等价查询。另外,还学习了如何在Access中创建和管理一对一、一对多和多对多关系。   本章前面部分主要介绍的是数据库管理的话题,这一部分的“Access工作台”将主要介绍Access中的数据库安全问题。本节,我们将学习如下内容: ● 理解Access中的数据库安全 ● 理解Access安全中工作组信息的角色 ● 使用Access Security Wizard来实现基本的数据库安全 ● 使用其他Access安全工具来管理数据库安全 6.8.1 Access中的数据库安全   虽然您可能不知道,但是Access中含有一个内置的安全系统,而且一旦使用了Access,那么这个安全系统就始终在运行。Access在一个工作组信息文件中存储了默认的安全设置,该文件名为system.mwb,存放在Windows系统文件C:\WINDOWS\system32\ system.mwb中。其他工作组信息文件(.mwb文件)还可以用来保护个别数据库或数据库组,但是在进行“Access工作台”这一部分所介绍的步骤之前,一定要对原始的system.mwb文件进行备份!如果没有正确的备份,该文件把事情弄乱了,那么使用Access时将真的会出现问题。目前所需要做的所有事情就是把system.mwb文件复制到My Documents文件夹中。   使用Tools| Security | User and Group Accounts菜单命令可以查看默认工作组信息文件中默认的内容。   浏览默认的安全设置: ● 注意:警告!您是否已经对system.mwb文件进行了备份?如果还没有,那么现在赶快做吧!把它复制到My Documents文件夹中。   (1) 启动Access,但是不要打开任何数据库。   (2) 单击Access主菜单中的Tools,然后单击Security,最后选择Tools菜单中的User and Group Accounts,这时弹出如图AW-6-1所示的User and Group Accounts对话框。 图AW-6-1 User and Group Accounts对话框   (3) 单击Name:下拉菜单。注意,此时在System-Admin中只有一个用户账户。   (4) 注意对话框中有两个组——Admins和Users,Admins同时是两个组的成员。   (5) 单击OK按钮,关闭该对话框。   虽然您可能并不知道,但是现在已经在以Admin的身份(无需密码)运行Access,因此,此时您就拥有了Access中管理员的所有特权。既然此时Admin账户没有密码,那么就不一定非要登录了。若此时给Admin增加一个密码(注意,图AW-6-1中的对话框中还有一个Change Login Password标签),以后每次启动Access时,还要以Admin身份登录,那么就必须输入相应的密码。   因此,使用用户登录和密码,Access就有能力处理用户身份验证的问题。Access在DBMS级别上也能进行用户的身份验证。而且,Access身份验证和授权的安全设置还可以运用到个人的数据库中。虽然可以手工完成上述工作,但如果使用Access Security Wizard来设置数据库安全和学习安全系统的功能,那么工作将会变得更加简单。在Access中,Wizard的名字不尽相同,它还被称为Security Wizard、User-Level Security Wizard以及One-step Security Wizard等。这里统称其为Security Wizard或是Wizard,但是请小心随后步骤中其他的称呼。因此,不管下面将如何称呼Wizard,这里将使用Wizard来保护WMCRM数据库,请注意将碰到哪些情况。   保护WMCRM数据库: ● 注意:最后警告!您是否已经对system.mwb文件进行了备份?如果还没有,那么现在赶快做吧!   (1) 打开WMCRM数据库。   (2) 单击Access主菜单中的Tools,然后单击Security并选择Tools菜单中的User Level Security Wizard。此时将弹出Security Wizard对话框,如图AW-6-2所示。 图AW-6-2 用户账户和用户组账户对话框   (3) 仔细阅读Security Wizard对话框中的信息,这时我们正在为该数据库创建一个新的工作组信息文件(*.mwb文件)。Access不但将保护该数据库,还将创建并存储一个不受保护的副本作为备份。   (4) 单击Next按钮,进入到Wizard下一个页面。   (5) 如图AW-6-3所示,接下来创建了一个新的工作组信息文件。该文件默认的名字为Security.mwb,位于My Documents文件夹中。文件的名称和位置很合理,因此这里将采用该默认的名称和位置。类似的,这里还使用了Access生成的WID。最后,把公司名称Wallingford Motors输入到Company文本框中。 图AW-6-3 创建工作组信息文件   (6) 注意,可以把新的工作组信息文件作为默认文件赋给所有的Access数据库,也可以把它用于本数据库。这里只把该文件用于本数据库。Wizard将创建一个桌面快捷菜单的图标,以便可以使用新的工作组信息文件打开WMCRM数据库。   (7) 单击Next按钮,进入到Wizard的下一个页面。   (8) 如图AW-6-4所示,接下来将要指定想要保护的数据库对象。默认情况下,Access将保护所有的对象——包括已经存在的数据库对象以及在数据库受到保护后创建的所有新对象。这种情况刚好是我们现在所需要的,因此在该页面上无需做任何修改。 图AW-6-4 指定包含的数据库对象   (9) 单击Next按钮,进入到Wizard的下一个页面。   (10) 如图AW-6-5所示,Access已经预定义了可以包含在安全设置中的安全组。图AW-6-6总结了与每个组相关的权限。 图AW-6-5 指定包含的安全组 组 授予组的权限 Backup Operators 该组可以专门为了备份操作和压缩数据库而打开该数据库,但是不能看到数据库中的任何对象 Full Data Users 该组拥有编辑数据库数据的所有权限,但是无法改变任何数据库对象的设计 Full Permissions 该组拥有对所有数据库对象的所有权限,但是不能把数据库权限赋予其他用户 New Data Users 该组可以读取和插入数据,但是不能修改数据库对象的设计,也不能删除或更新数据库数据 Project Designers 该组拥有编辑数据库数据和数据库对象的所有权限,但是不能改变数据库表及其之间的关系 Read-Only Users 该组可以读取数据库数据,但是不能改变任何数据库对象的设计,也不能插入、删除或更新数据库数据 Update Data Users 该组可以读取和更新数据库数据,但是不能改变任何数据库对象的设计,也不能插入或删除数据库数据 图AW-6-6 Access安全组权限汇总   (11) 这里将包含所有这些组,因此单击每个组的复选框,选中所有组。   (12) 单击Next按钮,进入到Wizard的下一个页面。   (13) 如图AW-6-7所示,Security Wizard提供了赋予工作站用户权限的选项。注意,工作站用户组指的是Windows操作系统的组,该组自动包括了工作站上所有的用户账户。授予该组权限意味着把使用数据库的权限赋予了工作站上所有拥有用户账户的人。本示例不会授予这种对WMCRM数据库的访问权限,因为我们只想让特定的用户拥有使用该数据库的权限。单击Next按钮,进入到Wizard的下一个页面。 图AW-6-7 为工作站上的用户组设置权限   (14) 接下来创建数据库的用户账户,该过程如图AW-6-8所示。这里将使用用户WMCRM中的昵称作为登录名,并给其设定一个密码,该密码包括:用户首字母,一个加号(+)以及单词password。比如,Tina Smith用户名的昵称是Tina,她的密码就是TS+password。通过该方法,为Wallingford Motors公司所有3位销售人员创建用户账户。 图AW-6-8 创建用户   (15) 为Wallingford Motors数据库管理员创建用户账户,其用户名为WM-Admin,其非标准的(即与前面介绍的密码创建规则不同)密码是Admin+password。这里不得不使用该密码,因为此时Access只允许至少14个字母的密码。   (16) 最后,注意名为Auer的用户已位于用户列表中。在Security Wizard运行时,它将为运行Wizard的开发人员自动创建一个拥有所有管理员特权的账户。既然现在是我在运行Wizard,那么它将使用我的Windows工作站操作系统的登录名Auer来为我创建一个账户。那么在您运行Wizard时,您将自动获得一个为您创建的User账户,您的用户名也将出现在该列表中。   (17) 单击Next按钮,进入Wizard的下一个页面。   (18) 现在是指派组成员关系的时候了。这里的原则是把用户指派给组,授予组相应的权限。如果是通过组进行授权的,那么永远不要直接授予用户权限。同时,您不一定受限于默认的用户组,可以根据需要手动地创建自己的组。组成员关系的指派方法有两种——可以把用户指派给组,或者组可以指定用户作为其成员。把用户指派给组的方法如图AW-6-9所示。注意,拥有对数据库完全管理权利的Admins组并没有出现在前面图AW-6-5和图AW-6-7中组的列表中。Admins是一个Access组,而不是数据库特定的组,它总是包含在每个安全任务集中。把WM-Admin指派到Admins组中。 图AW-6-9 为用户分配组的所属关系   (19) 仍然在同一个Wizard的页面中,单击Select a group and assign user to the group单选按钮,得到的页面如图AW-6-10所示。此时,从下拉菜单中选择一个组,然后把用户指派给它。对于本示例而言,选择Full Data Users组,并把Tina、Big Bill和Billy指派给该组。 图AW-6-10 把用户成员指派给组   (20) 单击Next按钮,进入Wizard的下一个页面。   (21) 这是Security Wizard的最后一个页面。要求对数据库未受保护的备份进行命名,并指定保存的位置。备份默认的名称为WMCRM.bak(与最初的数据库名称相同,只是以.bak作为扩展名),默认的保存位置为My Documents文件夹。这里没有必要改变默认的名称和位置。   (22) 同时,Wizard页面还会发出警告:将显示一个记录了安全工作已经完成的报表。单击Finish按钮,结束Security Wizard页面。   (23) 此时,One-Step Security Wizard Report出现在Security Wizard窗口中。如果需要的话,您可以使用Print Preview工具栏中的Print按钮或使用File| Print菜单命令打印该报表。然而,还有更好的方法来关闭Security Wizard窗口。在关闭Security Wizard窗口时,将弹出一个如图AW-6-11所示的Security Wizard警告,询问是否要把该报表保存为Snapshot(.snp)文件。 图AW-6-11 Security Wizard警告对话框   (24) 单击Security Wizard警告对话框中的Yes按钮。于是,One-Step Security Wizard Report文件将被命名为WMCRM.snp,并保存在My Documents文件夹中。图AW-6-12展示了该文件在Snapshot Viewer中的情形。 图AW-6-12 One-Step Security Wizard Report文件   (25) 单击窗口底部滚动条上的Print按钮,或使用File| Print菜单命令,可以打印One-Step Security Wizard Report文件。   (26) 关闭Snapshot Viewer。   (27) Security Wizard显示一个提示对话框,告知用户:要想使用被保护的数据库,必须结合新的工作组信息文件(My Documents文件夹中的security.mwb)来进行。要达到该目的,必须先关闭Access,然后重新启动。单击OK按钮,关闭该对话框。   (28) 关闭Access。 ● 注意:又一次警告!下面将要备份另一个非常重要的文件——现在请按如下步骤进行!   (29) 注意,Security Wizard已经把WMCRM.mdb快捷图标放到了Windows桌面上。现在要备份该快捷图标,因此右击WMCRM.mdb快捷图标,然后单击Copy。   (30) 单击Start| My Documents,打开My Documents窗口(这是一个Windows XP命令,用到了Windows XP Start菜单)。右击窗口空白处的任意处,显示一个快捷菜单,然后单击Paste Shortcut。于是,WMCRM.mdb快捷图标被复制到My Documents窗口中。 ● 注意:需要使用该备份来保护新的快捷图标。这一点在计算机实验室中特别重要。在计算机实验室中,当用户登录后,动态地创建工作站用户账户,然后在用户注销出去时从工作站中删除该用户账户,这些是很常见的。此时,桌面快捷图标也将随着其他账户信息一起删除。在这种情况下,用户的My Documents文件夹通常存放在网络服务器上,因此刚刚进行备份得到的副本将是很安全的。请与导师一起查看计算机实验室的正确程序。 6.8.2 受保护数据库的使用   既然我们已经使用了Security Wizard来保护WMCRM数据库,那么下面将使用到该受保护的数据库。然而,受保护数据库的使用并不一定像它听起来那么简单明了。注意,Security Wizard已经在Windows桌面上创建了一个名为WMCRM.mdb(Access数据库文件的名称)的快捷图标。该图标的特性已被设置为在打开数据库时,自动使用工作组信息文件(security.mwb)。但Access程序自身仍然要使用原始的system.mwb工作组信息文件!请注意尝试在Access中而不是通过快捷图标打开WMCRM数据库时所发生的情形。   打开受保护WMCRM数据库的错误方法: ● 注意:最后一次警告!您是否备份了system.mwb文件?如果还没有,赶快做吧!   (1) 打开Access。   (2) 尝试打开WMCRM数据库——此时将出现如图AW-6-13所示的令人恼火的出错信息。 图AW-6-13 “You Don’t Have the Necessary Permissions to Use This File”对话框   (3) 单击OK按钮,关闭该对话框。   (4) 关闭Access。   之所以产生出错信息,是因为Access自己使用的位于system.mwb工作组信息文件中的权限并不是运行WMCRM数据库所必需的权限——这些权限位于My Documents文件夹中的security.mwb工作组信息文件中。   接下来,试着使用快捷图标打开WMCRM数据库。   打开受保护WMCRM数据库的正确方法: ● 注意:还需要再问吗?请备份system.mwb文件。   (1) 双击Windows桌面上的WMCRM.mdb快捷图标。   (2) 此时弹出如图AW-6-14所示的Access Login对话框。 图AW-6-14 Access Login对话框   (3) 在Name文本框中输入用户登录名WM-Admin。   (4) 在Password文本框中输入密码Admin+password。   (5) 单击OK按钮。   (6) 此时出现常见的Security Warning对话框。单击Open按钮。   (7) 在Access中打开WMCRM数据库。   (8) 关闭WMCRM数据库。   虽然可以手动地把Access自身与WMCRM数据库使用的位于My Documents中的security.mwb工作组信息文件连接起来1,但是随后Access中使用的所有数据库都要在这些安全设置下工作。虽然我们要处理的数据库可能不想要这些安全设置,但这里不会修改默认的工作组信息文件。 6.8.3 受保护数据库的管理   如果需要,还可以手动修改WMCRM安全设置。用户账户和组的成员是通过Tools| Security| User and Group Accounts菜单命令来进行管理的。这时将弹出前面看到的User and Group Account对话框(参见图AW-6-1)。用户账户和组的权限是通过Tools| Security| User and Group Permissions菜单命令来进行管理的。该命令将显示如图AW-6-15所示的User and Group Permissions对话框。 图AW-6-15 User and Group Permissions对话框 6.8.4 关闭数据库并退出Access   本步骤将结束“Access工作台”这一部分的工作。与前相同,本步骤将关闭数据库和Access。   关闭WMCRM数据库:   (1) 如果WMCRM数据库仍然开着,那么单击WMCRM:Database窗口右上角的Close按钮。   退出Acces:   (1) 要想退出Access,只需单击Microsoft Access窗口右上角的Close按钮。 6.9 小结   数据库管理是一种商业功能,对于组织来说,它的目的就是通过管理而使数据库实现它的最大价值。保护数据库和允许用户最大程度地利用它是一种矛盾,因此需要通过良好的管理在这二者之间达到平衡。   所有的数据库都需要数据库管理功能。小型的、个人数据库的管理可能并不正规,但是大型的、多用户的数据库管理则可能需要整个办公室和大批人员来实现。DBA的缩写可以代表数据库管理或者数据库管理员。   并发控制的目的就是确保一个用户的操作不会对另一个用户的工作产生不良的影响。但是,没有一种并发控制系统能够适用于任何情况。因此需要在安全性和吞吐量之间进行权衡。   事务(或者逻辑工作单元)是对数据库进行处理时采用的一系列操作,作为原子单元执行;要么所有的操作都得以执行,要么不执行任何操作。并发事务的操作在服务器上交叉进行。有时,如果对并发操作不加以控制,就会丢失对数据库的更新。另一种并发问题是不一致读取。   脏读取是指事务读取了已经发生变化但还没有向数据库提交的数据。不可重复读取是指操作中重新读取已经读取过的数据时,却发现数据已经被其他的事务修改或者删除了。幻象读取是指事务重新读取已经读取过的数据时,发现其他的事务已经在数据中插入了新的数据行。   通过锁定数据库元素可以避免并发操作过程中出现的问题。隐式锁定由DBMS执行,而显式锁定则由应用程序执行。被锁定资源的规模称为锁定粒度。排它锁定禁止其他用户读取被锁定的内容,而共享锁定则允许其他用户读取已锁定的内容,但是禁止他们修改已锁定的内容。   当两个事务并发运行产生的结果与分别运行产生的结果一致时,我们称这两个事务为串行事务。串行事务采用了两段锁定机制,在增生阶段进行锁定,而在收缩阶段释放锁定。两段锁定的一个特例就是在整个事务执行过程中进行锁定,直到事务执行完成后才释放锁定。   当两个事务都在等待另外一个事务占用的资源时,就会发生死锁(也称为致命包含)。可以通过要求事务同时获得所需资源的所有锁定来避免死锁。一旦发生了死锁,唯一的方法就是中断其中的一项事务(意味着停止部分已经完成的工作)。   乐观锁定假定不会发生事务冲突,并按照这个假定来处理结果。悲观锁定假定会发生事务冲突,并且需要在冲突发生之前将事务锁定。一般来说,Internet和其他内部网应用程序更加倾向于使用乐观锁定。   许多应用程序并不显式地声明锁定,它们在事务边界上标记BEGIN、COMMIT、ROLLBACK等事务语句,并且声明它们所需采取的并发行为。然后,DBMS就会在应用程序中设置锁定,从而获得期望的行为。ACID事务是一种原子的、一致的、隔离的、持久的事务,持久性意味着数据库的改动是永久性的。一致性意味着语句级一致性或事务级一致性。在事务级一致性中,事务本身看不到自身的变化。   1992年推出的SQL标准定义了4个隔离级别:读取未提交、读取提交、可重复读取和可串行化隔离级别。有关这4种隔离级别的特性,请参见图6-13。   游标指的是指向一组记录的游标。目前普遍使用的游标有4种:只向前游标、静态游标、键集游标和动态游标。开发人员应选择与应用程序工作量和使用中DBMS产品相适应的隔离级别和游标种类。   数据库安全的目的在于确保只有授权的用户才可以在授权期间进行授权操作。为了确保数据库安全有效,必须确定所有用户的处理权限和责任。   DBMS产品都提供了安全机制,其中大部分包括对用户、组和受保护对象的声明,以及这些对象的权限和特权。基本上所有的DBMS产品都使用用户名和密码安全机制。DBMS安全可以通过应用程序安全得到改善。   在系统发生故障时,数据库必须尽量恢复到可用状态。发生故障时正在处理的事务必须重新执行或重新启动。虽然有时可以通过重新处理来实现数据恢复,但是人们常常更倾向于根据日志、前像、后像来执行前滚或回滚操作,以恢复数据。检查点可用来减少出现故障后的数据恢复的工作量。   除了并发控制、安全、备份和恢复之外,DBA需要确保有一个系统负责收集和记录各种问题和错误。DBA应当协同开发人员按照优先等级来解决这些问题,并测试DBMS新版本的特性和功能。此外,DBA还需要创建和管理一个控制数据库配置的进程,以便从全局的角度修改数据库结构。最后,DBA还需要确保正确维护一些文档,从而记录数据结构、并发控制、安全、备份和恢复,以及其他有关数据库管理和使用的信息。   分布式数据库是一种存储在多台计算机上并在其上进行处理的数据库。复制数据库指的是数据库部分或全部的多个副本储存在多台计算机上。分区数据库指的是数据库不同块分别储存在不同的计算机上。分布式数据库可以进行复制和分区。   分布式数据库带来很多处理上的挑战。如果数据库在某台单独的计算机上得到更新,那么随之而来的挑战只是确保数据库副本在逻辑上与其被分布时保持一致。然而,如果更新是在多台计算机上进行的,那么随之而来的问题就很严重了。如果数据库是经过分区而不是复制来分布的,那么在事务的数据横跨多台计算机时,就会出现问题。如果数据库是被复制的,而且更新发生在被复制的部分,那么此时就需要一种特殊的锁定算法,名为分布式两段锁定。实现该算法可能很困难,而且代价不菲。   对象由方法和属性或数值组成。给定类的所有对象都拥有相同的方法,但是却含有不同的属性值。对象持久化指的是存储对象属性值的过程。关系数据库很难达到对象持久化的目的。20世纪90年代,有人曾经开发了一些专门的产品,称作面向对象的DBMS,但是却一直没有获得商业上的认可。Oracle和其他一些公司扩展了其关系DBMS产品的功能,从而可以支持对象持久化。这些数据库又被称作面向对象的数据库。将来,可能会把XML用于对象持久化的目的,XML可能会取代对象-关系数据库的用途。 6.10 复习题   6.1 数据库管理的目的是什么?   6.2 说明为什么数据库管理任务会因为数据库规模和复杂程度而有所不同。   6.3 缩略语DBA分别代表哪两种意思?   6.4 并发控制的目的是什么?   6.5 数据库安全系统的目标是什么? 6.6 说明“一个用户的工作不会对另外一个用户的工作产生不良影响”一句中“不良影响”的含义。   6.7 说明并发控制中为什么要采取折衷方案。   6.8 说明原子事务的含义,并且说明“原子性”的重要性。   6.9 说明并发事务和同时进行的事务之间的区别。处理同时进行的事务需要多少CPU?   6.10 除了本书列举的示例,请再举一个示例以说明丢失更新问题。   6.11 给出脏读取、不可重复读取和幻象读取的定义。   6.12 说明“显式锁定”和“隐式锁定”的区别。 6.13 什么是锁定粒度?   6.14 说明排它锁定和共享锁定之间的区别。   6.15 什么是两段锁定? 6.16 说明在事务结束时释放所有锁定和两段锁定之间的关系。   6.17 什么是死锁?如何避免死锁?发生死锁后如何解决?   6.18 说明乐观锁定和悲观锁定之间的区别。   6.19 说明标记事务边界、声明锁定特征以及令DBMS设置锁定的优点。   6.20 说明BEGIN、COMMIT和ROLLBACK TRANSACTION语句的用处。   6.21 说明 ACID事务的含义。   6.22 说明语句级一致性的含义。   6.23 说明事务级一致性的含义以及它的缺点。   6.24 说明事务隔离级别的意义所在。   6.25 说明“读取未提交”隔离级别的含义,并举例说明它的用处。   6.26 说明“读取已提交”隔离级别的含义,并举例说明它的用处。   6.27 说明“可重复读取”隔离级别的含义,并举例说明它的用处   6.28 说明“可串行化”隔离级别的含义,并举例说明它的用处。   6.29 解释术语“游标”的含义。 6.30 说明为什么一个事务可能会有很多游标。同时,为何一个事务可能含有多个指向给定表的游标?   6.31 使用不同种类游标的好处是什么?   6.32 说明只向前游标的含义,并举例说明它的用处。   6.33 说明静态游标的含义,并举例说明它的用处。   6.34 说明键集游标的含义,并举例说明它的用处。   6.35 说明动态游标的含义,并举例说明它的用处。 6.36 如果没有声明DBMS的事务隔离级别和游标类型,将会发生什么情况?   6.37 说明定义处理权限和责任的必要性,并说明如何强制实施责任。   6.38 说明在普通的数据库安全系统中,用户、组、权限以及对象之间的关系。   6.39 说明DBMS提供的安全机制的优缺点。 6.40 说明应用程序提供的安全机制的优缺点。 6.41 说明数据库系统如何通过重新处理操作进行恢复。为什么这种方法一般来说不可行?   6.42 说明回滚和前滚的定义。   6.43 说明在更改数据库数据前写入日志的重要性。   6.44 描述回滚过程,并说明在什么情况下使用回滚操作。   6.45 描述前滚过程,并说明在什么情况下使用前滚操作。   6.46 阐述定期对数据库选取检查点的好处。   6.47 概括DBA在处理数据库用户问题上的职责。   6.48 概括DBA处理配置控制问题上的职责。   6.49 概括DBA处理文档的职责。   6.50 说明分布式数据库的含义。 6.51 如果数据库中含有3个表:T1、T2和T3,那么请说明给该数据库进行分区的方法。   6.52 如果数据库中含有3个表:T1、T2和T3,那么请说明复制该数据库的方法。   6.53 在完全复制数据库并只允许一台计算机处理更新的时候,必须做哪些工作?   6.54 如果多台计算机都可以更新被复制的数据库,则可能产生哪3个问题?   6.55 为了防止产生复习题6.54中的问题该采取什么措施?   6.56 对于分区而不是复制的分布式数据库,可能会产生什么问题。   6.57 在使用分布式数据库时,应该考虑哪些公司?   6.58 解释术语对象持久化的含义。   6.59 从一般的角度来分析为什么关系数据库很难用于关系持久化。   6.60 说明OODBMS的含义和用途。   6.61 根据本章内容,说明OODBMS没有获得成功的原因。   6.62 说明对象-关系数据库的含义。 6.11 练习题 6.63 在回答如下问题之前,请先打开Microsoft Access并在帮助文件中搜索sharing an Access database。     A. 总结共享Access数据库的方式。     B. 总结Access数据库的锁定机制。     C. 总结在Access共享数据库中设定选项的机制。 D. 在帮助文件中搜索backup and restore。总结Microsoft Access中可用的备份和恢复选项。   6.64 如果可以使用SQL Server,搜索它的帮助文件并回答以下问题。   A. SQL Server是否同时支持乐观锁定和悲观锁定?   B. 哪些事务隔离级别可用?   C. 如果存在的话,SQL Server支持哪些类型的游标?   D. SQL Server的安全模型与图6-17所示的模型有何不同。   E. 总结SQL Server备份的类型。   F. 总结SQL Server恢复的模型。   6.65 如果可以使用MySQL,搜索它的帮助文件并回答以下问题。   A. MySQL是如何使用读取锁定和写入锁定的?   B. MySQL可使用哪些事务隔离级别?   C. MySQL可使用哪些游标类型。   D. MySQL的安全模型与图6-17所示的模型有何不同?   E. 总结MySQL的备份功能。   F. 总结MySQL的恢复功能。 6.66 在Web上搜索术语分布式两段锁定(distributed two-phase locking)。找出关于该主题的辅导材料,并以通用的语言解释这种锁定算法是如何工作的。 6.67 访问www.Oracle.com,搜索关于对象-关系数据库的相关信息。解释术语列对象、嵌套表和行对象的含义。 6.12 Access工作台练习题 AW.6.1 在学习完“Access工作台:第六部分”的内容之后,现在在My Documents文件夹中就应该有5个与WMCRM数据库相关的字段(不包括在其他章节中对一些名称的修改)。指出这几个字段并说明其功能。 AW.6.2 通过电子数据表格记录下图AW-6-6中每个Access安全组的权限,其中安全组指的是WMCRM数据库中与表、查询、表单和报表有关的安全组。 AW.6.3 作为WMCRM Full Data Users组的成员,Wallingford Motors销售人员目前拥有的权限在WMCRM数据库是排它的。比如,目前销售人员可以修改SALESPERSON表中的数据,即他们可以修改他们自己的WageRate和CommissionRate的数值!请创建一个名为Contact Data Users的新安全组。要求该组拥有与Full Data Users组对CONTACT表和CUSTOMER表及其相关表单和报表相同的权限。但是,新组应该只有读取SALESPERSON和VIHICLE表中数据的能力。而且新组应该有权利运行已有的查询,但是不能创建新的查询,也不能修改或删除已有的查询。在创建该组之后,再向其中添加销售人员,并把销售人员的名单从Full Data Users组中删除。 AW.6.4 使用“Access工作台”前面章节中创建的Wedgewood Pacific Corporation的示例,完成如下问题: A. 分析WPC数据库表中的数据(特别是DEPARTMENT表和EMPLOYEE表),以图6-18为例创建一个数据库安全计划。 B. 运行WPC数据库的Access Security Wizard。在My Documents文件夹中保存一个新的工作组信息文件,命名为WPCsecurity.mdw。分别为James Nestor、Rick Brown、Mary Abernathy、Tom Caruthers和Heather Jones创建用户账户。使用“名的首字母加姓”的方法创建登录名,如James Nestor的登录名为JNestor。密码的创建则是使用了“姓名首字母‘+password’”的方法,如James Nestor的密码是JN+password。把所有这些用户都放到Full Data Users组中。打印One-Step Security Wizard Report,以便可以拥有一份安全设置的记录。 C. 在完成Security Wizard之后,在桌面上将出现一个名为WPC.mdb的快捷图标。保存一份该文件的副本到My Documents文件夹中。 D. 把步骤A中计划的数据库权限与赋予Full Data User组的权限进行比较,它们之间的匹配程度怎样?如果匹配的不是很好,那么请创建包含了一个或多个安全组的集合以实现安全计划并重新把用户分配到必需的组中。把所做的工作记录到一个书面的备忘录中,以便记录下必要的信息:创建了多少组,哪些用户被分配到相应的组中,授予了每个安全组哪些权限等。 6.13 Garden Glory项目问题   本书第3章中使用到的Garden Glory数据库设计为: OWNER (OwnerID, OwnerName, Email, Type) PROPERTY (PropertyID, PropertyName, Street, City, State, Zip, OwnerID) EMPLOYEE (Initials, Name, CellPhone, ExperienceLevel) SERVICE (PropertyID, Initials, Date, HoursWorked)   Garden Glory修改EMPLOYEE表,向其中添加了一个TotalHoursWorked列,如下所示: EMPLOYEE (Initials, Name, CellPhone, ExperienceLevel, TotalHoursWorked)   假定Garden Glory的办公室人员使用数据库应用程序来记录服务和相关数据的修改。对于一个新的服务,服务记录应用程序从PROPERTY表中读取一行,得到PropertyID。然后在SERVICE中创建一个新行,并把新的SERVICE记录中HoursWorked的值添加到EMPLOYEE表的TotalHoursWorked值中,以此更新TotalHoursWorked值。这个过程称为Service Update事务。   有时在记录服务之前,员工的记录还不存在。这时就需要为这个员工新建EMPLOYEE行,然后再记录服务。这个过程称为New Employee的Service Update事务。   A. 解释将Service Update事务改为原子性操作的重要性。   B. 描述在Service Update事务中丢失TotalHoursWorked更新的情况。 C. 假定需并发处理多个Service Update事务和多个New Employee 的Service Update事务,分别描述不可重复读取和幻象读取的情况。   D. 说明如何通过锁定来防止问题B中的丢失更新问题。 E. 在两个Service Update事务之间是否可能出现死锁?说明理由。在一个Service Update事务和一个New Employee的Service Update事务之间是否可能出现死锁?说明理由。   F. 对于Service Update事务,您觉得乐观锁定和悲观锁定哪一个更好一些。 G. 假定Garden Glory有3种用户:经理、行政人员和系统管理员。进一步假设管理人员的唯一工作就是处理Service Update事务。经理的工作则是处理Service Update事务和New Employee的Service Update事务。系统管理员可以对表进行任意操作。描述您认为适用于这种情况的处理权限。以图6-18为例,说明这种安全系统可能存在的问题。 H. Garden Glory开发了下面的过程来进行备份和恢复。公司每天晚上从服务器将数据库备份到公司网络上的另外一台计算机上,每个月将数据库刻录到CD上并将CD保存在经理的房间中。并且公司会保存一年以来所有服务的书面文件。如果数据库丢失,公司可通过备份和重新处理所有的服务请求来进行恢复。   您认为目前Garden Glory的备份和恢复程序是否可行?这个程序可能会出现什么问题?是否有其他解决方案?阐述您认为公司应该对这套系统进行改进的地方。 6.14 James River珠宝行项目问题   本书第3章中使用到的James River数据库设计为: CUSTOMER (CustomerID, LastName, FirstName, Phone, Email) PURCHASE (InvoiceNumber, Date, PreTaxAmount, CustomerID) PURCHASE_ITEM (InvoiceNumber, ItemNumber, RetailPrice) ITEM (ItemNumber, Description, Cost, ArtistName)   James River修改数据库,向其中添加了两个表——OWNER表和JEWELRY_ITEM表,如下所示: OWNER (OwnerID, Name, Phone, Email, AmountOwed) JEWELRY_ITEM (ItemNumber, DateReceived, DateSold, NegotiatedSalesPrice, ActualSalesPrice, CommissionPercentage, OwnerID)   其中: 要求JEWELRY_ITEM表中的OwnerID在OWNER表的OwnerID存在对应的项 JEWELRY_ITEM表中的ItemNumber在ITEM表的ItemNumber存在对应的项      这两个表用来记录和保存接收代售珠宝及货主的数据。其中JEWELRY_ITEM表(ITEM的子表,注意其参照完整性约束)用来记录约定的销售价格、代售的每件珠宝的佣金以及实际的销售价格。   假设James River的工作人员使用一个数据库应用程序来记录代售的数据。每当接到一件代售珠宝时,如果是新货主,货主的数据就会被存储下来;否则,就会采用已有的货主数据。此时创建ITEM和JEWELRY_ITEM新的行。在ITEM表中,记录了ItemNumber和Description,Cost设置为$0.00,如果有某个艺术家与该件珠宝有关,则输入ArtistName。对于JEWELRY_ITEM表来说,保存除DateSold列和ActualSalePrice列之外的其他所有数据。James River的工作人员称这个过程为Acceptance事务。之后,如果珠宝没有销售出去,NegotiatedSalesPrice和ComnissionPercentage值可能会降低。这个过程称为Price Adjustment事务。最后,如果出售了一件珠宝,则需要为这件珠宝的DateSold和ActualSalePrice列赋值,Owner表中的AmountOwed值也需要加上此珠宝的ActualSalesPrice值中货主所占的百分比值。这个过程称为Sales事务。   A. 解释将这些事务改为原子性事务的重要性。   B. 描述一个可能会丢失AmountOwed项更新的情况。   C. 描述不可重复读取和幻象读取的情况。   D. 说明如何通过锁定来防止问题B中的丢失更新问题。 E. 在两个Acceptance事务之间是否可能出现死锁?说明理由。是否可能在一个Acceptance事务和一个Sales事务中出现死锁?说明理由。   F. 对于这3种事务来说,您觉得乐观锁定和悲观锁定哪一个更好一些。说明理由。 G. 假定James River珠宝行有3组用户:经理、行政人员和系统管理员。进一步假设经理和行政人员都可以执行Acceptance事务和Sales事务,但只有经理可以执行Price Adjustment事务。描述您认为适用于这种情况的处理权限。以图6-18为例。 H. James River珠宝行开发了下面的过程来进行备份和恢复。公司每天晚上从服务器将数据库备份到公司网络上的另外一台计算机上,每个月将数据库刻录到CD上并将CD保存在经理的房间中。并且公司会保存一年以来所有服务的书面文件。如果数据库丢失,公司可通过备份和重新处理所有的服务请求来进行恢复。您认为目前James River珠宝行的备份和恢复程序是否可行?这个程序可能会出现什么问题?是否有其他解决方案?阐述您认为公司应该对这套系统进行改进的地方。 6.15 Queen Anne Curiosity商店项目问题   本书第3章中使用到的Queen Anne Curiosity商店的数据库设计为: CUSTOMER (CustomerID, LastName, FirstName, Address, City, State, ZIP, Phone, Email) EMPLOYEE (EmployeeID, LastName, FirstName, Phone, Email) VENDOR (VendorID, CompanyName, ContactLastName, ContactFirstName, Address, City, State, ZIP, Phone, Fax, Email) ITEM (ItemID, ItemDescription, PurchaseDate, ItemCost, ItemPrice, VendorID) SALE (SaleID, CustomerID, EmployeeID, SaleDate, SubTotal, Tax, Total) SALE_ITEM (SaleID, SaleItemID, ItemID, ItemPrice)   Queen Anne Curiosity商店已经对两个表ITEM和SALE_ITEM进行了修改,如下所示: ITEM (ItemID, ItemDescription, UnitCost, UnitPrice, QuantityOnHand, VendorID) SALE_ITEM (SaleID, SaleItemID, ItemID, Quantity, ItemPrice, Extended Price)   这些修改将允许销售系统能够处理那些可以按数量销售购买的非唯一的商品。当新的商品从供应商那里送到Queen Anne Curiosity商店时,办公室工作人员将打开商品包裹,把它们放到仓库中,然后运行Item Quantity Received事务,把收到的商品数量添加QuantityOnHand中。同时,如果需要调整UnitCost和UnitPrice,可以运行另一个名为Item Price Adjustment的事务。销售行为可能随时都会发生,当发生销售时,就需要运行Sale事务。每次输入SALE_ITEM时,就从QuantityOnHand中减去输入的Quantity,ItemPrice设定为UnitPrice。   A. 解释将这些事务改为原子性事务的重要性。   B. 描述一个可能会丢失QuantityOnHand项更新的情况。   C. 描述不可重复读取和幻象读取的情况。   D. 说明如何通过锁定来防止问题B中的丢失更新问题。 E. 在两个Sale事务之间是否可能出现死锁?说明理由。是否可能在一个Sale 事务和一个Quantity Recieved事务中出现死锁?说明理由。   F. 对于这3种事务来说,您觉得乐观锁定和悲观锁定哪一个更好一些。说明理由。 G. 假定Queen Anne Curiosity商店有4组用户:销售人员、经理、行政人员和系统管理员。进一步假设经理和行政人员都可以执行Item Quantity Received事务,但只有经理可以执行Item Price Adjustment事务。描述您认为适用于这种情况的处理权限。以图6-18为例。   H. Queen Anne Curiosity商店开发了下面的过程来进行备份和恢复。公司每周六晚上从服务器将整个数据库备份到磁带上。随后,该磁带将在下个周二被带到当地银行的保险箱中。打印出来的所有销售记录的书面文件将保存5年。如果数据库丢失,公司可通过最近一次完全备份和重新处理所有的服务请求来进行恢复。您认为目前Queen Anne Curiosity的备份和恢复程序是否可行?这个程序可能会出现什么问题?是否有其他解决方案?阐述您认为公司应该对这套系统进行改进的地方。         1 要想进行这样的连接,需使用Access的Tools| Security| Workgroup Administrator菜单命令。 ??      ??      ??      ??    308  第Ⅱ部分 数据库设计和管理    309 第6章 数据库管理