openGauss数据库设计与应用 课件 章永来 第6-8章 数据库的保护技术 -数据库设计与实现_第1页
openGauss数据库设计与应用 课件 章永来 第6-8章 数据库的保护技术 -数据库设计与实现_第2页
openGauss数据库设计与应用 课件 章永来 第6-8章 数据库的保护技术 -数据库设计与实现_第3页
openGauss数据库设计与应用 课件 章永来 第6-8章 数据库的保护技术 -数据库设计与实现_第4页
openGauss数据库设计与应用 课件 章永来 第6-8章 数据库的保护技术 -数据库设计与实现_第5页
已阅读5页,还剩476页未读 继续免费阅读

下载本文档

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

文档简介

第6章数据库的保护技术

数据库概论第6章数据库的保护技术6.1数据库的安全性6.2数据库的完整性6.3并发控制6.4数据库的恢复技术数据库的安全性是指保护数据库,防止不合法的使用,以免数据的泄露、更改和破坏。第6章数据库的保护技术6.1.1计算机系统安全性为计算机系统建立和采取的各种安全保护措施,以保护计算机系统中的硬件、软件及数据,防止因偶然或恶意的原因使系统遭到破坏,数据遭到更改或泄露等。1.计算机系统外部的安全问题(1)自然环境中的安全问题:如计算机机房、设备及其周边环境的安全问题、防火、防盗、防人为进行物理破坏等问题;(2)社会环境中的安全问题:如各种规章制度的制定问题、对相关人员的管理和安全性教育等问题;(3)设备环境中的安全问题:如设备的定期检查、维修及更新等问题。6.1.1计算机系统安全性(1)计算机系统中的安全问题:如病毒的侵入、黑客的攻击等;(2)操作系统中的安全问题:如防止未经授权通过操作系统进入数据库系统,进行非法操作;(3)数据库系统中的安全问题:如用户的身份确认问题、数据库的操作权限问题;(4)应用系统中的安全问题:如各种应用程序本身存在的一些安全漏洞问题等。2.计算机系统内部的安全问题6.1.1计算机系统安全性6.1.2安全性控制的方法安全性控制就是要尽可能地杜绝所有可能的数据库非法访问。非法使用数据库的情况编写合法程序绕过DBMS及其授权机制直接或编写应用程序执行非授权操作通过多次合法查询数据库从中推导出一些保密数据6.1.2安全性控制的方法安全性不仅是数据库层面的,在计算机系统都存在这一问题。计算机系统中,安全措施是一级一级层层设置

图6-1安全控制模型6.1.2安全性控制的方法数据库安全性控制的常用方法用户标识和鉴别存取控制视图数据审计数据加密1.用户标识与鉴别用户标识与鉴别(Identification&Authentication)系统提供的最外层安全保护措施6.1.2安全性控制的方法身份(Identification)认证口令(Password)认证系统核对口令以鉴别用户身份

随机数运算(ComputeringofRandomNumber)认证每个用户预先约定好一个计算过程或者函数1.用户标识与鉴别6.1.2安全性控制的方法2.用户存取权限控制用户存取权限指的是不同的用户对于不同的数据对象允许执行的操作权限。存取控制机制组成定义用户权限合法权限检查用户权限定义和合法权检查机制一起组成了DBMS的安全子系统6.1.2安全性控制的方法3.视图机制把要保密的数据对无权存取这些数据的用户隐藏起来,对数据提供一定程度的安全保护主要功能是提供数据独立性,无法完全满足要求间接实现了支持存取谓词的用户权限定义6.1.2安全性控制的方法4.审计审计是一种监视措施,把用户对数据库的所有操作自动记录下来放入审计日志中。审计日志的内容:操作类型、操作终端标识、操作者标识、操作日期和时间、操作所涉及的相关数据、操作的前象和后象。DBA利用审计日志,找出非法存取数据的人、时间和内容。6.1.2安全性控制的方法5.数据加密数据加密防止数据库中数据在存储和传输中失密的有效手段加密方法替换方法置换方法混合方法DBMS中的数据加密6.1.2安全性控制的方法第6章数据库的保护技术6.1数据库的安全性6.2数据库的完整性

6.3并发控制6.4数据库的恢复技术6.2数据库的完整性数据库的完整性数据的正确性和相容性数据的完整性和安全性是两个不同概念数据的完整性防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据防范对象:不合语义的、不正确的数据数据的安全性保护数据库防止恶意的破坏和非法的存取防范对象:非法用户和非法操作根据完整性约束条件的作用对象和状态,数据库完整性约束可分为六类:列级静态约束元组级静态约束关系级静态约束列级动态约束元组级动态约束关系级动态约束6.2.1完整性约束条件的类型6.2.1完整性约束条件的类型(1)列级静态约束:是对属性值域的说明,即数据类型、数据格式和取值范围的约束。(2)元组级静态约束:是对元组各个属性值之间关系的约束。(3)关系级静态约束:是一个关系中各个元组之间或者若干个关系之间存在的各种联系的约束。常见的关系级静态约束有:实体完整性约束;参照完整性约束、函数依赖约束、统计依赖约束6.2.1完整性约束条件的类型(4)列级动态约束:是修改定义或属性值时应满足的约束条件,如将原来允许空值的属性修改为不允许空值时,如果该属性当前已存在空值,则将拒绝修改。(5)元组级动态约束:是修改某个元组的值时要参照该元组的原有值,新值和原有值之间应满足某种约束条件。(6)关系级动态约束:是关系新旧状态变化应满足的约束条件。如事务的一致性、原子性等约束条件。关系级动态约束实现时的开销较大。6.2.2完整性控制机制的功能

(1)定义功能:为用户提供定义完整性约束条件的命令或工具。(2)检查功能:能够自动检查用户发出的操作请求是否违背了完整性约束条件。(3)保护功能:当发现用户的操作请求使数据违背了完整性约束条件时,能够自动采取一定的措施确保数据的完整性不遭破坏。1.参照关系中的外键取值问题【例】设一个企业的数据库中有职工关系Employee和部门关系Depart,关系Employee的主键为职工号Eno,外键为部门号Dno关系Depart的主键为部门号DnoEmployee是参照关系,关系Depart为被参照关系在关系Employee中,当某一元组的Dno列值为空值,表示该职工尚未分配到任何具体的部门工作。这和具体实际的语义是相符的,因此,关系Employee的外键Dno列可以取空值。6.2.2完整性控制机制的功能

【例】在学生选课数据库中,有学生关系Student和选课关系SCSC为参照关系,外键为Sno,Student为被参照关系,其主键为Sno。若关系SC的外键Sno为空值,而其对应的成绩字段Grade中却有值,则表明尚不存在的某个学生选修了某门课程。这显然与实际情况是不相符的.因此,关系SC的外键Sno列值不能取空值。1.参照关系中的外键取值问题6.2.2完整性控制机制的功能

2.被参照关系中删除元组的问题(1)级联删除(CascadesDelete):就是将参照关系中所有外键值与被参照关系中要删除元组主键值相同的元组一起删除。如果被参照关系又是另一关系的参照关系,则这种删除操作会持续级联下去。(2)受限删除(RestrictedDelete):就是当参照关系中没有任何元组的外键值与被参照关系中要删除元组的主键值相同时,才允许执行此删除操作,否则拒绝执行这个删除操作。(3)置空值操作(NullifiesDelete):就是删除被参照关系的元组时,并将参照关系中与被参照关系中被删除元组主键值相等的外键值置为空值。6.2.2完整性控制机制的功能

例如:要删除Student关系中Sno=“0906064201”的元组,而SC关系中有3个元组的Sno都等于“0906064201”。级联删除:将SC关系中所有3个Sno=“0906064201”的元组一起删除。受限删除:系统将拒绝执行此删除操作。置空值删除:将SC关系中所有Sno=“0906064201”的元组的Sno值置为空值。2.被参照关系中删除元组的问题6.2.2完整性控制机制的功能

3.在参照关系中插入元组的问题(1)受限插入:仅当被参照关系中存在相应的元组,其主键值与参照关系插入元组的外键值相同时,系统才执行插入操作,否则拒绝此操作(2)递归插入:首先向被参照关系中插入相应的元组,其主键值等于参照关系插入元组的外键值,然后向参照关系插入元组。6.2.2完整性控制机制的功能

4.元组中主键值的修改问题(1)不允许修改键码:不允许进行主键值的修改。如果确实需要修改主键值,只能先删除该元组,再将具有新主键值的元组插入到关系中。(2)允许修改主键:允许进行主键值的修改,但必须保证主键的唯一性和非空性。6.2.2完整性控制机制的功能

例如:将Student关系中Sno=“0906064201”的元组中Sno值改为“0906064215”。而SC关系中有3个元组的Sno=“0906064201”。级联修改:将SC关系中3个Sno=“0906064201”元组中的Sno值也改为“0906064215”。如果参照关系同时又是另一个关系的被参照关系,则这种修改操作会继续级联下去。受限修改:只有SC中没有任何元组的Sno=“0906064201”时,才能修改Student表中Sno=“0906064201”的元组的Sno值改为“0906064215”。置空值修改:将Student表中Sno=“0906064201”的元组的Sno值改为“0906064215”。而将SC表中所有Sno=“0906064201”的元组的Sno值置为空值。4.元组中主键值的修改问题6.2.2完整性控制机制的功能

6.2.3完整性设计原则(1)根据数据库完整性约束的类型确定其实现的系统层次和方式,并提前考虑对系统性能的影响。一般情况下,静态约束应尽量包含在数据库模式中,而动态约束由应用程序实现。(2)实体完整性约束、参照完整性约束是关系数据库最重要的完整性约束,在不影响系统关键性能的前提下需尽量应用。(3)要慎用目前主流DBMS都支持的触发器功能,一方面由于触发器的性能开销较大,另一方面,触发器的多级触发不好控制,容易发生错误。(4)在需求分析阶段就必须制定完整性约束的命名规范,尽量使用有意义的英文单词、缩写词、表名、列名及下划线等组合,使其易于识别和记忆。(5)要根据业务规则对数据库完整性进行细致的测试,以尽早排除隐含的完整性约束间的冲突和对性能的影响。(6)要有专职的数据库设计小组,自始至终负责数据库的分析、设计、测试、实施及早期维护。数据库设计人员不仅负责基于DBMS的数据库完整性约束的设计实现,还要负责对应用软件实现的数据库完整性约束进行审核。(7)应采用合适的CASE工具来降低数据库设计各阶段的工作量。6.2.3完整性设计原则6.2.4触发器

触发器(Trigger)是用户定义在关系表上的一类由事件驱动的特殊过程由服务器自动激活可以进行更为复杂的检查和操作,具有更精细和更强大的数据控制能力

1.定义触发器CREATETRIGGER语法格式

CREATETRIGGER<触发器名>{BEFORE|AFTER}<触发事件>ON<表名>FOREACH{ROW|STATEMENT}

[WHEN<触发条件>]

<触发动作体>6.2.4触发器

定义触发器的语法说明:1.创建者:表的拥有者2.触发器名3.表名:触发器的目标表4.触发事件:INSERT、DELETE、UPDATE5.触发器类型行级触发器(FOREACHROW)语句级触发器(FOREACHSTATEMENT)6.2.4触发器

定义触发器的语法说明:6.触发条件触发条件为真省略WHEN触发条件7.触发动作体触发动作体可以是一个匿名SQL过程块也可以是对已创建存储过程的调用6.2.4触发器

【例】定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。

CREATETRIGGERInsert_Or_Update_SalBEFOREINSERTORUPDATEONTeacher

/*触发事件是插入或更新操作*/FOREACHROW

/*行级触发器*/ASBEGIN/*定义触发动作体,是PL/SQL过程块*/IF(new.Job='教授')AND(new.Sal<4000)THENnew.Sal:=4000;ENDIF;END; 6.2.4触发器

【例】定义AFTER行级触发器,当教师表Teacher的工资发生变化后就自动在工资变化表Sal_log中增加一条相应记录

首先建立工资变化表Sal_logCREATETABLESal_log(EnoNUMERIC(4)referencesteacher(eno),

SalNUMERIC(7,2),

Usernamechar(10),

DateTIMESTAMP);6.2.4触发器

CREATETRIGGERInsert_Sal

AFTERINSERTONTeacher/*触发事件是INSERT*/FOREACHROWASBEGININSERTINTOSal_logVALUES(new.Eno,new.Sal,CURRENT_USER,CURRENT_TIMESTAMP);END;6.2.4触发器

CREATETRIGGERUpdate_Sal

AFTERUPDATEONTeacher/*触发事件是UPDATE*/FOREACHROWASBEGINIF(new.Sal<>old.Sal)THENINSERTINTOSal_logVALUES(new.Eno,new.Sal,CURRENT_USER,CURRENT_TIMESTAMP);ENDIF;END;6.2.4触发器

2.激活触发器触发器的执行,是由触发事件激活的,并由数据库服务器自动执行一个数据表上可能定义了多个触发器同一个表上的多个触发器激活时遵循如下的执行顺序:(1)执行该表上的BEFORE触发器;(2)激活触发器的SQL语句;(3)执行该表上的AFTER触发器。6.2.4触发器

【例】执行修改某个教师工资的SQL语句,激活上述定义的触发器。

UPDATETeacherSETSal=800WHEREEname='陈平';

执行顺序是:执行触发器Insert_Or_Update_Sal执行SQL语句“UPDATETeacherSETSal=800WHEREEname='陈平';”执行触发器Insert_Sal;执行触发器Update_Sal

6.2.4触发器

2.激活触发器3删除触发器删除触发器的SQL语法:

DROPTRIGGER<触发器名>ON<表名>;触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除。【例】删除教师表Teacher上的触发器Insert_SalDROPTRIGGERInsert_SalONTeacher;6.2.4触发器

1.空值(NULL)约束【例】创建student表,要求SNO、SNAME、SSEX字段为NOTNULL,SDEPT字段为NULL。CREATETABLEstudent(SNOCHAR(10)NOTNULL,SNAMECHAR(8)NOTNULL,SDEPTCHAR(10)NULL)6.2.5数据完整性控制2.默认(DEFAULT)约束定义默认约束的格式为:CREATETABLEtable_name/*指定表名*/(column_namedatatypeNOTNULL|NULL[DEFAULTconstraint_expression]/*默认值约束表达式*/[,…n])6.2.5数据完整性控制【例】创建student表,定义系名字段SDEPT的默认约束CREATETABLEstudent(SNOCHAR(10)NOTNULL,SNAMECHAR(8)NOTNULL,SSEXBITNOTNULL,SDEPTCHAR(10)DEFAULT“网络工程”)6.2.5数据完整性控制2.默认(DEFAULT)约束在定义默认约束时指定了约束名。CREATETABLEstudent(SNOCHAR(10)NOTNULL,SNAMECHAR(8)NOTNULL,SSEXBITNOTNULL,SDEPTCHAR(10)CONSTRAINTsdept_defaultDEFAULT“网络工程”)6.2.5数据完整性控制2.默认(DEFAULT)约束【例】删除student表中的默认约束。

ALTERTABLEstudentDROPCONSTRAINTsdept_default2.默认(DEFAULT)约束6.2.5数据完整性控制3.检查(CHECK)约束定义检查约束的格式为:

CREATETABLEtable_name/*指定表名*/(column_namedatatypeNOTNULL|NULL[[check_name]CHECK(logical_expression)]/*CHECK约束表达式*/[…n])/*定义列名、数据类型、标识列、是否空值和CHECK约束*/6.2.5数据完整性控制【例6-20】创建books表,其中书的价格字段BOOK_VALUE的取值范围0~200。CREATETABLEbooks(BOOK_IDSMALLINT,/*书号*/BOOK_NAMEVARCHAR(50)/*书名*/BOOK_VALUETINYINT

CHECK(BOOK_VALUE>=0ANDBOOK_VLAUE<=200)/*书的价格约束*/)3.检查(CHECK)约束6.2.5数据完整性控制在修改表时也可创建CHECK约束,其格式为:

ALTERTABLEtable_nameADDCONSTRAINTcheck_nameCHECK(logic_expression)参数含义:关键字ADDCONSTRAINT表示在已定义的table_name表中增加一个约束定义约束名由check_name指定约束条件表达式为logic_expression。3.检查(CHECK)约束6.2.5数据完整性控制【例】增加SC表中成绩字段GRADE的CHECK约束,要求GRADE字段取值为0~100。

ALTERTABLESCADDCONSTRAINTgrade_constraintCHECK(GRADE<=0ANDGRADE<=100)3.检查(CHECK)约束6.2.5数据完整性控制删除CHECK约束的格式为:

ALTERTABLEtable_nameDROPCONSTRAINTcheck_name功能:在table_name指定的表中,删除名为check_name的约束。3.检查(CHECK)约束6.2.5数据完整性控制【例】删除SC表中,成绩字段GRADE的CHECK约束。

ALTERTABLESCDROPCONSTRAINTgrade_constraint3.检查(CHECK)约束6.2.5数据完整性控制4.主键(PRIMARYKEY)约束创建PRIMARYKEY约束的格式为:CREATETABLEtable_name/*指定表名*/(column_namedatatype/*定义字段*/[CONSTRAINTconstraint_name]/*定义约束名*/NOTNULLPRIMARYKEY/*定义主键约束*/[CLUSTERED|NONCLUSTERED]

/*定义约束的索引类型*/[,…n])/*n表示可定义多个字段*/6.2.5数据完整性控制【例】建立一个SC表,其中属性列SNO和CNO组成SC的主键。

CREATETABLESC(SNOCHAR(10)NOTNULL,CNOCHAR(10)NOTNULL,GRADENUMERIC(3),

CONSTRAINTSC_PRIMPRIMARYKEY(SNO,CNO))4.主键(PRIMARYKEY)约束6.2.5数据完整性控制通过修改表也可创建PRIMARYKEY约束,格式为:

ALTERTABLEtable_nameADD[CONSTRAINTconstraint_name]PRIMARYKEYCLUSTERED|NONCLUSTERED(column[,…n])4.主键(PRIMARYKEY)约束6.2.5数据完整性控制【例】对表student中SNO字段创建PRIMARYKEY约束。

ALTERTABLEstudentADDCONSTRAINTS_PKPRIMARYKEYCLUSTERDE(SNO)4.主键(PRIMARYKEY)约束6.2.5数据完整性控制删除PRIMARYKEY约束的格式为:

ALTERTABLEtable_nameDROPCONSTRAINTconstraint_name[,…n]4.主键(PRIMARYKEY)约束6.2.5数据完整性控制【例】删除例子中建立的PRIMARYKEY约束。

ALTERTABLESCDROPCONSTRAINTSC_PRIM4.主键(PRIMARYKEY)约束6.2.5数据完整性控制5.唯一(UNIQUE)约束唯一性约束用于指定一个或多个列的组合值具有唯一性,以防止在列中输入重复的值。定义了UNIQUE约束的那些列称为唯一键,系统自动为唯一键建立唯一索引,从而保证了唯一键的唯一性。PRIMARYKEY约束与UNIQUE约束的相同点在于:二者均不允许表中对应的字段存在重复值。6.2.5数据完整性控制PRIMARYKEY约束与UNIQUE约束的主要区别:(1)一个基本表只能创建一个PRIMARYKEY约束,但一个基本表可根据需要对不同的列创建若干个UNIQUE约束;(2)PRIMARYKEY字段的值不允许为NULL,而UNIQUE字段值可以取NULL;(3)一般创建PRIMARYKEY约束时,系统会自动产生索引,索引的默认类型为簇索引,创建UNIQUE约束时,系统会自动产生一个UNIQUE索引,索引的默认类型为非簇索引。5.唯一(UNIQUE)约束6.2.5数据完整性控制创建UNIQUE约束的格式为:CREATETABLEtable_name/*指定表名*/(column_namedatatype/*定义字段*/[CONSTRAINTconstraint_name]/*定义约束名*/NOTNULLUNIQUE/*定义主键约束*/[CLUSTERED|NONCLUSTERED]/*定义约束的索引类型*/[,…n])/*n表示可定义多个字段*/5.唯一(UNIQUE)约束6.2.5数据完整性控制【例】创建student表,其中SNAME字段具有唯一性。

CREATETABLEstudent(SNOCHAR(8),SNAMECHAR(10),SSEXCHAR(2),CONSTRAINTPK_SNOPRIMARYKEY(SNO),

CONSTRAINTUK_SNAMEUNIQUE(SNAME))5.唯一(UNIQUE)约束6.2.5数据完整性控制通过修改表也可创建UNIQUE约束,格式为:ALTERTABLEtable_nameADD[CONSTRAINTconstraint_name]UNIQUECLUSTERDE|NONCLUSTERED(column[,…n])5.唯一(UNIQUE)约束6.2.5数据完整性控制【例】对表student中的SNAME创建UNIQUE约束。

ALTERTABLEstudentADDCONSTRAINTs_UKUNIQUENONCLUSTERDE(SNAME)

删除UNIQUE约束的格式与删除PRIMARYKEY约束的格式相同。【例】删除例6-8创建的UNIQUE约束。

ALTERTABLEstudentDROPCONSTRAINTUK_SNAME5.唯一(UNIQUE)约束6.2.5数据完整性控制6.外键(FOREIGNKEY)约束定义外键约束的格式为:

CREATETABLEtable_name(colunm_namedatatype[FOREIGNKEY]REFERENCESref_table(ref_column)[…n])6.2.5数据完整性控制【例】定义student表中的SNO为主键,SC表中的SNO为外键。

CREATETABLEstudent(SNOCHAR(10)NOTNULLCONSTRAINTSNO_PKPRIMARYKEY,SNAMECHAR(8)NOTNULL,SDEPTCHAR(10)NULL)CREATETABLESC(SNOCHAR(10)NOTNULLFOREIGNKEYREFERENCESstudent(SNO),CNOCHAR(6)NOTNULL,GRADESMALLINT)6.外键(FOREIGNKEY)约束6.2.5数据完整性控制通过修改表也可定义外键约束,其格式为:ALTERTABLEtable_nameADD[CONSTRAINTconstraint_name]FOREIGNKEY(column[,…])REFERENCESref_table(ref_colunm[,…n])6.外键(FOREIGNKEY)约束6.2.5数据完整性控制【例】课程表course为主表,course.CNO为主键,SC表为从表,将SC中的CNO字段定义为外键。

ALTERTABLESCADDCONSTRAINTc_foreignFOREIGNKEY(CNO)REFERENCEScourse(CNO)6.外键(FOREIGNKEY)约束6.2.5数据完整性控制【例】删除上例中SC表中的外键约束。

ALTERTABLESCDROPCONSTRAINTc_foreign6.外键(FOREIGNKEY)约束6.2.5数据完整性控制第6章数据库的保护技术6.1数据库的安全性6.2数据库的完整性6.3并发控制6.4数据库的恢复技术6.3并发控制多用户数据库系统的存在允许多个用户同时使用的数据库系统飞机定票数据库系统银行数据库系统特点:在同一时刻并发运行的事务数可达数百个不同的多事务执行方式

(1)事务串行执行每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行不能充分利用系统资源,发挥数据库共享资源的特点T1T2T3事务的串行执行方式6.3并发控制(2)交叉并发方式在单处理机系统中,事务的并行执行是这些并行事务的并行操作轮流交叉运行单处理机系统中的并行事务并没有真正地并行运行,但能够减少处理机的空闲时间,提高系统的效率6.3并发控制事务的交叉并发执行方式6.3并发控制6.3并发控制(3)同时并发方式多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务,实现多个事务真正的并行运行6.3并发控制事务并发执行带来的问题会产生多个事务同时存取同一数据的情况可能会存取和存储不正确的数据,破坏事务一致性和数据库的一致性6.3.1事务的基本概念1.事务定义

2.事务的特性定义一个数据库操作序列一个不可分割的工作单位恢复和并发控制的基本单位事务和程序比较在关系数据库中,一个事务可以是一条或多条SQL语句,也可以包含一个或多个程序。一个程序通常包含多个事务1.事务(Transaction)6.3.1事务的基本概念显式定义方式

BEGINTRANSACTIONBEGINTRANSACTIONSQL语句1SQL语句1

SQL语句2SQL语句2

。。。。。。。。。。

COMMITROLLBACK隐式方式当用户没有显式地定义事务时,DBMS按缺省规定自动划分事务1.事务(Transaction)6.3.1事务的基本概念2.事务的ACID特性原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)6.3.1事务的基本概念3.事务例子BEGINTRANSACTION

READAA=A-RIFA<0

/*A中款数不足*/

THENBEGINDISPLAY“A中款数不足”

ROLLBACKENDELSE

/*拨款*/BEGINB=B+RDISPLAY“拨款完成”

COMMITEND6.3.1事务的基本概念6.3.2并发操作引发的问题设存款余额M=2000元,事务T1取款500元,事务T2取款300元。T1包含三个操作:读取余额(READM);计算余额(M=M-500);更新余额(UPEATEM)。T2也包含三个操作:读取余额(READM);计算余额(M=M-300);更新余额(UPEATEM)。如果T1和T2顺序执行,最后的存款余额应该是1200元。1.丢失更新丢失更新是指当两个事务T1和T2读入同一数据,并发执行修改操作时,T2把T1或T1把T2的修改结果覆盖掉,造成了数据的不一致问题。这个问题是由于两个事务对同一数据并发地进行写入所引起的,因而又被称为写-写冲突(Write-wtiteConflict)。在银行取款的例子中,如果T1和T2按表6-5所示顺序执行,最后得到错误结果M=1700元,原因是丢失了T1对数据库的更新操作。6.3.2并发操作引发的问题顺序事务T1M在数据库中的值事务T21ReadM20002ReadM3M=M-5004M=M-3005UpdateM150061700UpdateM6.3.2并发操作引发的问题1.丢失更新2.读“脏”数据读“脏”数据问题(DirtyRead)是指事务T1更新了某一数据,并将修改后的值写入磁盘,事务T2读取了更新后的数据,其后事务T1由于某种原因被撤销,事务T1已更新过的数据恢复原值,这样事务T2读到的数据就与数据库中的数据不一致,是不正确的数据,称为“脏”数据。这种由于一个事务读取另一个更新事务尚未提交的数据引起的不一致问题,又被称为读-写冲突(Read-writeConflict)。6.3.2并发操作引发的问题顺序事务T1M在数据库中的值事务T21ReadM2000M=M-500UpdateM15002ReadM3Rollback20002.读“脏”数据6.3.2并发操作引发的问题3.不可重复读不可重复读(UnrepeatableRead)是指事务T1读取数据后,事务T2进行读取并进行更新操作,使T1再次读取该数据进行校验时,发现两次读取的数据值不一致,它也是由于读-写冲突引起的。6.3.2并发操作引发的问题不可重复读有三种情形:(1)事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时,得到与前一次不同的值。表6-7中说明的就是这种情况。在银行取款的例子中,如果事务T1和T2按表6-4所示顺序执行,则T1第一次读取的M值为2000,第二次读取的M值为1500,二者值不一致。(2)事务T1按一定条件从数据库中读取某些数据记录后,事务T2删除了其中的部分记录,当事务T1再次按相同条件读取数据时,发现某些记录已经不存在了。(3)事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些记录,当事务T1再次按相同条件读取数据时,发现多了一些记录。3.不可重复读6.3.2并发操作引发的问题顺序事务T1M在数据库中的值事务T21ReadM200021500ReadMM=M-500UpdateM3ReadM15003.不可重复读6.3.2并发操作引发的问题6.3.2并发操作引发的问题数据不一致性:由于并发操作破坏了事务的隔离性并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性实现并发控制的方法主要是基于封锁的并发控制技术6.3.3封锁的概念及类型1、什么是封锁2、基本封锁类型3、锁的相容矩阵4、封锁协议1、什么是封锁封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。6.3.3封锁的概念及类型2、基本封锁类型一个事务对某个数据对象加锁后究竟拥有什么样的控制由封锁的类型决定。基本封锁类型排它锁(ExclusiveLocks,简记为X锁)共享锁(ShareLocks,简记为S锁)6.3.3封锁的概念及类型排它锁又称为写锁若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁保证其他事务在T释放A上的锁之前不能再读取和修改A2、基本封锁类型6.3.3封锁的概念及类型共享锁又称为读锁若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁保证其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改2、基本封锁类型6.3.3封锁的概念及类型3、锁的相容矩阵Y=Yes,相容的请求N=No,不相容的请求

T2T1XS-XNNYSNYY-YYY6.3.3封锁的概念及类型6.3.4封锁协议在运用X锁和S锁对数据对象封锁时,需要约定一些规则:封锁协议(LockingProtocol)何时申请X锁和S锁持锁时间、何时释放不同的封锁协议,在不同程度上为并发操作的正确调度提供了一定的保证常用的封锁协议:三级封锁协议1、一级封锁协议事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放正常结束(COMMIT)非正常结束(ROLLBACK)一级封锁协议可防止丢失修改在一级封锁协议中,如果是读数据,不需要加锁的,所以它不能保证可重复读和不读“脏”数据。6.3.4封锁协议顺序T1T2M在数据库中的值1XlockM获得ReadM=200020002XlockMWait3M=M-500WriteM=1500CommitUnlockMWaitWaitWait

15004

获得XlockMreadM=1500M=M-300WriteM=1200CommitUnlockM

12001、一级封锁协议6.3.4封锁协议顺序T1T2M在数据库中的值1

XlockM获得ReadM=2000M=M-500WriteM=1500

2000

15002

ReadM=150015003ROLLBACKUnlockM

2000依然发生读“脏”数据的问题1、一级封锁协议6.3.4封锁协议一级封锁协议+事务T在读取数据R前必须先加S锁,读完后即可释放S锁。二级封锁协议可以防止丢失修改和读“脏”数据。在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。2、二级封锁协议6.3.4封锁协议2、二级封锁协议-防止读“脏”数据顺序T1T2M在数据库中的值1XlockM获得ReadM=2000M=M-500WriteM=15002000

15002SlockM3ROllBACKUnlockMWaitWait20004SlockM获得ReadM=2000UnlockMCommit6.3.4封锁协议2、二级封锁协议-“不可重复读”问题顺序T1T2M的值N的值1

SlockM,N获得ReadM=2000ReadN=1000UnlockM,NXlockNWaitWaitWait获得2000

1000

2M+N=3000SlockM得到SlockNWaitWait获得ReadN=1000N=N+200WriteN=1200CommitUlockN

12003ReadM=2000ReadN=1200M+N=3200(验算错误)

6.3.4封锁协议3、三级封锁协议一级封锁协议+事务T在读取数据R前必须先加S锁,直到事务结束才释放S锁。三级封锁协议可防止丢失修改,读“脏”数据和不可重复读。6.3.4封锁协议3、三级封锁协议-防止不可重复读顺序T1T2M的值N的值1SlockM,N获得ReadM=2000ReadN=1000M+N=3000XlockNWaitWaitWaitWait200010002ReadM=2000ReadN=1000M+N=3000CommitUnlockNWaitWaitWaitWait获得ReadN=1000N=N+200WriteNCommitUnlockN12006.3.4封锁协议封锁协议小结三级协议的主要区别什么操作需要申请封锁何时释放锁(即持锁时间)6.3.4封锁协议封锁协议小结6.3.4封锁协议6.3.5活锁与死锁封锁技术可以有效地解决并行操作的一致性问题,但也带来一些新的问题死锁活锁1.活锁事务T1封锁了数据R事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待。T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求……T2有可能永远等待,这就是活锁的情形6.3.5活锁与死锁T1T2T3T4……nLockA……LockA……waitUnlockAwaitLockA……wait……wait……waitUnlockALockAwaitLockAwaitLockAwait……1.活锁6.3.5活锁与死锁避免活锁:采用先来先服务的策略当多个事务请求封锁同一数据对象时按请求封锁的先后次序对这些事务排队该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁1.活锁6.3.5活锁与死锁2.死锁事务T1封锁了数据R1T2封锁了数据R2T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁接着T2又申请封锁R1,因T1已封锁了R1,T2也只能等待T1释放R1上的锁这样T1在等待T2,而T2又在等待T1,T1和T2两个事务永远不能结束,形成死锁6.3.5活锁与死锁2.死锁-示例T1T2SlockA1SlockA2XlockA2Wait……XlockA1Wait……6.3.5活锁与死锁解决死锁的两类方法(1)

预防死锁(2)

死锁的诊断与解除2.死锁6.3.5活锁与死锁(1)预防死锁产生死锁的原因是两个或多个事务都已封锁了一些数据对象,然后又都请求对已为其他事务封锁的数据对象加锁,从而出现死等待。预防死锁的发生就是要破坏产生死锁的条件6.3.5活锁与死锁一次封锁法顺序封锁法(1)预防死锁6.3.5活锁与死锁一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行存在的问题降低系统并发度难于事先精确确定封锁对象6.3.5活锁与死锁(1)预防死锁顺序封锁法顺序封锁法是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁。顺序封锁法存在的问题维护成本数据库系统中封锁的数据对象极多,并且在不断地变化。难以实现:很难事先确定每一个事务要封锁哪些对象

6.3.5活锁与死锁(1)预防死锁(2)

死锁的诊断与解除死锁的诊断超时法事务等待图法6.3.5活锁与死锁超时法如果一个事务的等待时间超过了规定的时限,就认为发生了死锁优点:实现简单缺点有可能误判死锁时限若设置得太长,死锁发生后不能及时发现(2)

死锁的诊断与解除6.3.5活锁与死锁等待图法用事务等待图动态反映所有事务的等待情况事务等待图是一个有向图G=(T,S)T为结点的集合,每个结点表示正运行的事务U为边的集合,每条边表示事务等待的情况若T1等待T2,则T1,T2之间划一条有向边,从T1指向T2(2)

死锁的诊断与解除6.3.5活锁与死锁事务等待图等待图法(2)

死锁的诊断与解除6.3.5活锁与死锁解除死锁选择一个处理死锁代价最小的事务,将其撤消释放此事务持有的所有的锁,使其它事务能继续运行下去(2)

死锁的诊断与解除6.3.5活锁与死锁6.3.6可串行化调度与两段锁协议

DBMS对并发事务不同的调度可能会产生不同的结果1、什么样的调度是正确的?2、如何保证并发操作的调度是正确的?

1、什么样的调度是正确的?计算机系统对并行事务中并行操作的调度是随机的,而不同的调度会产生不同的结果。将所有事务串行起来的调度策略一定是正确的调度策略。如果一事务运行过程中没有其它事务在同时运行,也就是说它没有受到其它事务的干扰,那么就可以认为该事务的运行结果是正确的或者预想的。6.3.6可串行化调度与两段锁协议

以不同顺序串行执行事务也有可能会产生不同的结果,但由于不会使数据库置于不一致状态,所以都可以认为是正确的。6.3.6可串行化调度与两段锁协议

1、什么样的调度是正确的?可串行化(Serializable)调度多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行这些事务时的结果相同可串行性(Serializability)是并发事务正确调度的准则一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度6.3.6可串行化调度与两段锁协议

1、什么样的调度是正确的?【例】现在有两个事务,分别包含下列操作:T1:读Y;X=Y+10;写回X;T2:读X;Y=X+10;写回Y;现给出对这两个事务不同的调度策略6.3.6可串行化调度与两段锁协议

1、什么样的调度是正确的?对这两个事务的不同调度策略串行执行串行调度策略1串行调度策略2交错执行不可串行的调度可串行化的调度6.3.6可串行化调度与两段锁协议

1、什么样的调度是正确的?保证并发操作调度正确性的方法封锁方法:两段锁协议2.如何保证并发操作的调度是正确的?6.3.6可串行化调度与两段锁协议

两段锁协议两段封锁协议(Two-PhaseLocking,简称2PL)是最常用的一种封锁协议,理论上证明使用两段封锁协议产生的是可串行化调度6.3.6可串行化调度与两段锁协议

指所有事务必须分两个阶段对数据项加锁和解锁在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁在释放一个封锁之后,事务不再申请和获得任何其他封锁6.3.6可串行化调度与两段锁协议

两段锁协议事务分为两个阶段第一阶段是获得封锁,也称为扩展阶段事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁第二阶段是释放封锁,也称为收缩阶段事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁6.3.6可串行化调度与两段锁协议

两段锁协议事务T1的封锁序列是:

SlockX…XlockY…XlockZ…UnlockX…UnlockZ…UnlockY;事务T2的封锁序列是:

XlockX…UnlockX…XlockY…XlockZ…UnlockZ….UnlockY;则事务T1遵守两段锁协议,而事务T2不遵守两段锁协议。6.3.6可串行化调度与两段锁协议

两段锁协议两段锁协议与防止死锁的一次封锁法一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议但是两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁6.3.6可串行化调度与两段锁协议

两段锁协议两段锁协议与三级封锁协议两类不同目的的协议两段锁协议保证并发调度的正确性三级封锁协议在不同程度上保证数据的一致性遵守第三级封锁协议必然遵守两段锁协议6.3.6可串行化调度与两段锁协议

第6章数据库的保护技术6.1数据库的安全性6.2数据库的完整性6.3并发控制6.4数据库的恢复技术

6.4.1数据库恢复技术1.数据转储2.日志文件转储是指DBA将整个数据库复制到磁带或另一个磁盘上保存起来的过程,备用的数据称为后备副本或后援副本如何使用数据库遭到破坏后可以将后备副本重新装入重装后备副本只能将数据库恢复到转储时的状态1.数据转储6.4.1数据库恢复技术2.日志文件什么是日志文件日志文件的格式和内容6.4.1数据库恢复技术什么是日志文件

日志文件(log)是用来记录事务对数据库的更新操作的文件6.4.1数据库恢复技术2.日志文件日志文件的格式和内容日志文件的格式以记录为单位的日志文件以数据块为单位的日志文件6.4.1数据库恢复技术2.日志文件6.4.2数据库恢复策略1.事务故障的恢复2.系统故障的恢复3.介质故障的恢复1.事务故障的恢复事务故障:事务在运行至正常终止点前被终止恢复方法由恢复子系统应利用日志文件撤消(UNDO)此事务已对数据库进行的修改事务故障的恢复由系统自动完成,对用户是透明的,不需要用户干预6.4.2数据库恢复策略事务故障的恢复步骤1)反向扫描文件日志(即从最后向前扫描日志文件),查找该事务的更新操作。2)对该事务的更新操作执行逆操作。即将日志记录中“更新前的值”写入数据库。插入操作,“更新前的值”为空,则相当于做删除操作删除操作,“更新后的值”为空,则相当于做插入操作若是修改操作,则相当于用修改前值代替修改后值1.事务故障的恢复6.4.2数据库恢复策略3)继续反向扫描日志文件,查找该事务的其他更新操作,并做同样处理。4)如此处理下去,直至读到此事务的开始标记,事务故障恢复就完成了。事务故障的恢复步骤1.事务故障的恢复6.4.2数据库恢复策略2.系统故障的恢复系统故障造成数据库不一致状态的原因未完成事务对数据库的更新已写入数据库已提交事务对数据库的更新还留在缓冲区没来得及写入数据库恢复方法1)Undo故障发生时未完成的事务2)Redo已完成的事务系统故障的恢复由系统在重新启动时自动完成,不需要用户干预6.4.2数据库恢复策略检查点技术检查点记录的内容1)建立检查点时刻所有正在执行的事务清单2)这些事务最近一个日志记录的地址重新开始文件的内容记录各个检查点记录在日志文件中的地址2.系统故障的恢复6.4.2数据库恢复策略具有检查点的日志文件和重新开始文件检查点技术2.系统故障的恢复6.4.2数据库恢复策略3.介质故障的恢复1)重装数据库2)重做已完成的事务6.4.2数据库恢复策略6.4.3数据库的镜像介质故障是对系统影响最为严重的一种故障,严重影响数据库的可用性介质故障恢复比较费时为预防介质故障,DBA必须周期性地转储数据库提高数据库可用性的解决方案数据库镜像(Mirror)数据库镜像DBMS自动把整个数据库或其中的关键数据复制到另一个磁盘上DBMS自动保证镜像数据与主数据库的一致性每当主数据库更新时,DBMS自动把更新后的数据复制过去(如下图所示)6.4.3数据库的镜像6.4.3数据库的镜像思考内容

第7章关系数据库的设计理论

(2025秋季学期)

数据库概论第7章关系数据库的设计理论关系数据库逻辑设计针对具体需求,如何构造一个合适的数据模式(二维表)第7章关系数据库的设计理论7.1关系模式的设计问题7.2数据的函数依赖7.3关系数据库模式的规范化理论7.4关系模式分解算法7.1关系模式的设计问题

关系模式由五部分组成,即它是一个五元组:R(U,D,DOM,F)R:关系名U:组成该关系的属性名集合D:属性组U中属性所来自的域DOM:属性向域的映象集合F:属性间数据依赖关系集合7.1.1数据依赖关系模式R(U,D,DOM,F)简化为一个三元组:

R(U,F)7.1.2数据依赖对关系模式的影响[例]建立一个描述学生信息的数据库,该数据库涉及的对象包括学生的学号(Sno)、所在系(Sdept)、系主任姓名(Mname)、课程名(Cname)和成绩(Grade)。单一的关系模式:Student<U、F>U={Sno,Sdept,Mname,Cname,Grade}

属性组U上的一组函数依赖F:

F={Sno→Sdept,Sdept→Mname,(Sno,Cname)→Grade}

SnoCnameSdeptMnameGrade7.1.2数据依赖对关系模式的影响U={Sno,Sdept,Mname,Cname,Grade}

存在的问题

数据冗余太大

插入问题

删除问题

更新问题7.1.2数据依赖对关系模式的影响结论:Student关系模式不是一个好的模式。“好”的模式:不会发生插入异常、删除异常、更新异常,数据冗余应尽可能少。原因:由存在于模式中的某些数据依赖引起的。解决方法:通过分解关系模式来消除其中不合适的数据依赖。7.1.2数据依赖对关系模式的影响第7章关系数据库的设计理论7.1关系模式的设计问题

7.2数据的函数依赖7.3关系数据库模式的规范化理论7.4关系模式分解算法7.2.1函数依赖1.定义设R(U)是一个属性集U上的关系模式,X和Y是U的子集。若对于r中任意两个元组s和t,当s[X]=t[X]时,就有s[Y]=t[Y],则称属性子集X函数决定属性子集Y或者称Y函数依赖于X,记为X→Y。否则就称X不函数决定Y或者称Y不函数依赖于X,记为X↛Y。如果X→Y,且Y→X,则记为X←→Y。如果X→Y,则称X为决定因素(determinant)。注意:

所有关系实例均要满足语义范畴的概念数据库设计者可以对现实世界作强制的规定7.2.1函数依赖【例7-1】图书管理系统中的图书借阅关系模式为R(读者编号,姓名,图书编号,书名,借书日期),由现实世界的语义可知,读者编号唯一,图书编号唯一,姓名和书名可以重复出现。求其函数依赖。

函数依赖:读者编号→姓名,图书编号→书名,(读者编号,图书编号)→借书日期7.2.1函数依赖【例7-2】指出学生关系S(学号,姓名,图书证号,系别,系主任)中存在的函数依赖关系。关系S中存在下列函数依赖:学号→姓名(每个学号只能有一个学生姓名)

学号→系别(每个学号只能在一个系)

学号→图书证号(每个学号只能有一个图书证号)

系别→系主任(每个系只能由一名系主任)7.2.1函数依赖2.函数依赖的3种基本情形(1)平凡与非平凡函数依赖在关系模式R(U)中,对于U的子集X和Y,如果X→Y,但Y

X,则称X→Y是非平凡的函数依赖若X→Y,但Y

X,则称X→Y是平凡的函数依赖【例7-3】在关系SC(Sno,Cno,Grade)中,非平凡函数依赖:(Sno,Cno)→

Grade

平凡函数依赖:(Sno,Cno)→

Sno(Sno,Cno)→Cno7.2.1函数依赖(2)部分与完全函数依赖定义在R(U)中,如果X→Y,并且对于X的任何一个真子集X’,都有X’Y,则称Y对X完全函数依赖,记作XFY。若X→Y,但Y不完全函数依赖于X,则称Y对X部分函数依赖,记作XPY。

7.2.1函数依赖2.函数依赖的3种基本情形(2)部分与完全函数依赖

【例7-4】关系SC(Sno,Cno,Sname,Grade)

中(Sno,Cno)→Grade是完全函数依赖,

(Sno,Cno)→Sname是部分函数依赖因为Sno→Sname成立,且Sno是(Sno,Cno)的真子集。

7.2.1函数依赖2.函数依赖的3种基本情形

(3)传递与直接函数依赖定义在R(U)中,如果X→Y,(Y

X),Y→XY→Z,

则称Z对X传递函数依赖。记为:X→Z

注意:如果Y→X,即X←→Y,则Z直接依赖于X。【例7-5】

在关系S(学号,姓名,图书证号,系别,系主任)中,有:学号→系别,系别→系主任,则系主任传递函数依赖于学号。传递7.2.1函数依赖2.函数依赖的3种基本情形

7.2.2依赖的逻辑蕴含定义设F是在关系模式R上成立的函数依赖的集合,X→Y是一个函数依赖。如果对于R的每个满足F的关系r也满足X→Y,那么称F逻辑蕴含X→Y,记为F=>X→Y。(用已知函数依赖判断其他的函数依赖)定义设F是函数依赖集,被F逻辑蕴含的函数依赖全体构成的集合,称为函数依赖集F的闭包(closure),记为F+。即F+={X→Y|F=>X→Y}7.2.3Armstrong公理系统

关系模式R<U,F>来说有以下的推理规则:(1)自反律(Reflexivity):若Y

X

U,则

X→Y为F所蕴含。(2)增广律(Augmentation):若X→Y为F所蕴含,且Z

U,则XZ→YZ为F所蕴含。(3)传递律(Transitivity):若X→Y及Y→Z为F所蕴含,则X→Z为F所蕴含。Armstrong公理具有如下两个性质:

有效性:由F出发根据Armstrong公理推导出的每一个函数依赖X→Y必定在F+中。

完备性:F+中的每一个函数依赖X→Y,必定可以由F出发,根据Armstong公理推导出。7.2.3Armstrong公理系统7.2.3Armstrong公理系统(1)合并律(unionrule):如果X→Y和X→Z成立,那么X→YZ成立,即若F⇒X→Y,F⇒X→Z,则F⇒X→YZ。(2)伪传递律(pseudotransivityrule):如果X→Y和WY→Z成立,那

温馨提示

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

评论

0/150

提交评论