码迷,mamicode.com
首页 > 数据库 > 详细

关系模式设计理论 - 数据库系统原理

时间:2017-01-04 07:24:03      阅读:429      评论:0      收藏:0      [点我收藏+]

标签:属性   条件   第一范式   不一致   这一   解决   规范化   推导   元组   

       模式设计理论主要包括三方面的内容:数据依赖范式模式设计方法。数据依赖研究数据之间的联系,起着核心的作用;范式是关系模式的标准;模式设计方法是自动化设计的基础。

 

关系模式的设计准则

  • 关系模式的冗余和异常

       关系模式的冗余指数据冗余。数据冗余 指同一个数据在系统中多次重复出现,这一直是影响系统性能的大问题。在文件系统中由于文件之间没有联系,一个数据会在多个文件中出现。数据库系统克服了文件系统的这种缺陷。

       由于数据冗余,对数据操作时就会引起各种异常修改异常插入异常删除异常。例如,关系模式 R(S#,C#,CNAME,TNAME)。一门课程有多名学生选修,CNAME,TNAME 就会重复出现多次,这就是数据冗余。修改一门课的名称或任课老师,就必须修改所有相关元祖,否则就会出现数据不一致。新增一门新课时,尚无学生选修,由于 S# 是主键,不能为空值,会造成插入异常。

       “分解”是解决冗余的主要方法,也是规范化的一条原则:“关系模式有冗余问题,就分解它”。将上述关系模式分解为为 R1(S#,C#),R2(C#,CNAME,TNAME)两个关系模式,就解决了冗余问题,消除了操作异常。这样的分解是否最佳,也不是绝对的,如果要查学生的任课老师,就要对两个关系作连接操作,连接是有性能代价的。

 

  • 关系模式的四个非形式化设计准则
  1. 关系模式的设计应尽可能只包含有直接联系的属性,不要包含有间接联系的属性。也就是说,每个关系模式应只对应于一个实体类型或一个联系类型。
  2. 关系模式的设计应尽可能使得相应关系中不出现插入、删除和修改等操作异常现象。如果出现任何异常,则要清楚的加以说明,并确保更新数据库的程序正确操作。
  3. 关系模式的设计应尽可能使得相应关系中避免放置经常为空值的属性。
  4. 关系模式的设计应尽可能使得关系的等值连接在主键和外键的属性上进行,并且保证连接以后不会生成额外的元组。

 

函数依赖(FD)

       在数据依赖中,函数依赖是最基本,最重要的一种依赖。

  • 函数依赖的定义

       设有关系模式 R(A1,A2,…,An)或简记为 R(U),X,Y 是 U 的子集,r 是 R 的任一具体关系,如果对 r 的任意两个元组 t1 和 t2,由 t1[X] = t2[X] 导致 t1[Y] = t2[Y],则称 X 函数决定 Y,或 Y 函数依赖于 X,记为 X → Y。X → Y 为模式 R 的一个函数依赖。

       这个定义可以这样理解:有一张设计好的二维表,X,Y 是表的某些列(可以是一列,也可以是多列),若在表中的第 t1 行,和第 t2 行上的 X 值相等,那么必有 t1 行和 t2 行的 Y 值也相等,这就是说 Y 函数依赖于 X,X 决定 Y。

       例1,有一学生选课,教师任课数据的关系模式:R(S#,SNAME,AGE,SEX,C#,CNAME,SCORE,T#,TNAME,TITLE)。

根据常识,可以写出下列 FD 形式:S# →  SNAME,C# → CNAME,(S#,C#) → SCORE,T# → (TNAME,TITLE)等。

       例2,关系模式 R(ABCD),在 R 的关系中,属性值间有这样的联系:A 值与 B 值有一对多联系,C 值 与 D 值有一对一联系。试写出相应的函数依赖。

B → A,C ←→ D  // 当 X → Y 和 Y → X 同时成立,可以写成 X ←→ Y

  • 函数依赖的逻辑蕴涵

       设 F 是关系模式 R 的一个函数依赖集,X,Y 是 R 的属性子集,如果从 F 中的函数依赖能够推出 X → Y,则称 F 逻辑蕴涵 X → Y,记为 F |= X → Y。

       这个定义可以这样理解:一个关系模式可能有多个函数依赖形成函数依赖集,现在有一个新的函数依赖不在函数依赖集里,但如果能从集合里根据一定的规则推导出来,就说这个函数依赖集逻辑蕴涵这个新的函数依赖。比如,“根据身份证号能确定出生年月和性别”是已知的函数依赖,这就能推导出“根据身份证号能确定出生年月”,就说“根据身份证号能确定出生年月和性别”逻辑蕴涵“根据身份证号能确定出生年月”。

       函数依赖的闭包 F+(加号是上标是指被 F 逻辑蕴涵的函数依赖的全体构成的集合

  • FD 的推理规则

       从已知的一些 FD 可以推导出另外一些 FD,这就需要一系列推理规则。FD 的推理规则最早出现在 1974 年 W.W.Armstrong 的论文里。

       设有关系模式 R(U),X,Y,Z,W 均是 U 的子集,F 是 R 上只涉及到 U 中属性的函数依赖集,推理规则如下:(? 读作包含于,? 读作包含,开口方向的范围大)

  1. 自反性:如果 Y ? X ? U,则 X –> Y 在 R 上成立。
  2. 增广性:如果 X –> Y 在 R 上成立且 Z ? U,则 XZ –> YZ 在 R 上成立。(XZ 表示 XUZ,U 符号表示“并”,就是两个集合并起来的意思)
  3. 传递性:如果 X –> Y 和 Y –> Z 在 R 上成立,则 X –> Z 在 R 上成立。
  4. 复合性:如果 X –> Y 和 W –> Z 成立,则 XW –> YZ 成立。
  5. 合并性:如果 X –> Y 和 X –> Z 成立,则 X –> YZ 成立。
  6. 伪传递性:如果 X –> Y 和 WY –> Z 成立,则 WX –> Z 成立。
  7. 分解性:如果 X –> Y 和 Z ? Y 成立,则 X –> Z 成立。
  8. 通用一致性:如果 X –> Y 和 W –> Z 成立,则 X U(W - Y) –> YZ 成立。

       例,设有关系模式 R,A、B、C、D、E、F 是它的属性集的子集,R 满足下列函数依赖: F = {A –> BC,CD –> EF},证明:函数依赖 AD –> F 成立。

       证明:因为 A –> BC,所以 A –> C(分解性); AD –> CD(增广性);因为 CD –> EF,所以 AD - EF(传递性);AD –> F(传递性)成立。

  • 平凡函数依赖

       当关系中属性集合 Y 是属性集合 X 的子集时(Y?X),若存在函数依赖 X → Y,即一组属性函数决定它的所有子集,这种函数依赖称为平凡函数依赖。

       如 (Sno, Cno) → Sno ,(Sno, Cno) → Cno,平凡 FD 并没有什么实际意义

  • 非平凡函数依赖

       当关系中属性集合 Y 不是属性集合 X 的子集时,存在函数依赖 X → Y,则称这种函数依赖为非平凡函数依赖。

       例如,在关系 SC(Sno, Cno, Grade)中: (Sno, Cno) → Grade,Grade 不是 (Sno, Cno)的子集,但 (Sno, Cno)函数决定 Grade。

  • FD 和关键码的联系

       设关系模式 R 的属性集是 U,X 是 U 的一个子集。如果 X –> U 在 R 上成立,那么称 X 是 R 的一个超键(在关系中能唯一标识元组的属性集)。如果 X –> U 在 R 上成立,但对于 X 的任一真子集 X1 有 X1 –> U 不成立,那么称 X 是 R 上的一个候选键(不含有多余属性的超键)。

       例如,关系模式:R(S#,SNAME,AGE,SEX,C#,CNAME,SCORE,T#,TNAME,TITLE)。根据已知的 FD 和 推理规则,可以知道(S#,C#)能函数决定 R 的全部属性,并且是一个候选键。虽然(S#,SNAME,C#,CNAME)也能函数决定 R 的全部属性,但相比之下,只能说是一个超键,因为其中有多余属性

  • 属性集的闭包

       说的白话一点,闭包就是由一个属性直接或间接推导出的所有属性的集合

       例如:设有函数依赖集 F= { A→D,AB→E,BI→E,CD→I,E→C },计算属性集 AE 关于 F 的闭包(AE)+。

       解题:首先,A+ 包括自己,再找函数依赖于 A 的属性,都加入A+;E 也是如此。所以, A+ = { A },由 A –> D 得到 A+ = { A,D},由 E –> C,所以 E+ = { E,C },则 AE+ = { A,C,D,E},再由 CD –> I,最终 AE+ = { A,C,D,E,I }。

  • FD 集的最小依赖

       满足下列条件的函数依赖集 F 称为最小函数依赖集:

  1. G 中每个 FD 的右边都是单属性。
  2. G 中没有冗余的 F,即 G 中不存在这样的函数依赖 X –> Y,使得 G - {X –> Y}与 G 等价。
  3. G 中每个 FD 的左边没有冗余的属性,即 G 中不存在这样的函数依赖 X –> Y,X 有真子集 W 使得 G - {X,Y} U {W –> Y}与 G 等价。

       例1:设 F 是关系模式 R(ABC) 的 FD 集,F = {A –> BC,B –> C,A –> B,AB –> C},求其最小依赖集。

  1. 首先,把 F 中的 FD 写成右边是单属性形式:F = {A –> B,A –> C,B –> C,A –> B,AB –> C},去除重复的 A –> B,得到: F = {A –> B,A –> C,B –> C,AB –> C}
  2. 去除冗余 FD。F 中 A –> C 可由 A –> B,B –> C 推导出,所以 A –> C 是冗余的,去除,同样,AB –> C 可由 B –> C 推出,也去除,最终:F = {A –> B,B –> C}

       求 FD 的最小依赖集的算法

  1. 根据推理规则的分解性,得到一个与 F 等价的 FD 集 G,G 中每个 FD 的右边都是单属性。
  2. 在 G 的每个 FD 中消除左边冗余的属性
  3. 消除 G 中的冗余 FD。

 

关系模式的分解特性

       对于存在数据冗余、插入异常、删除异常问题的关系模式,应采取分解为多个关系模式的方法进行处理,但这种分解过程必须是“可逆”的,即模式分解的结果应该能重新映像到分解前的关系模式。

       模式分解就是将一个泛关系模式 R 分解成数据库模式 p,以 p 代替 R 的过程。它不仅仅是属性集合的分解,它是对关系模式上的函数依赖以及关系模式的当前值进行分解的具体表现。

       下表将关系模式 R(ABC)分解成 p = {AB,AC},分解后的关系通过自然连接还原,未丢失信息,这种分解称为“无损分解”:

A

B

C

 

A

B

 

A

C

1

1

1

 

1

1

 

1

1

1

2

1

 

1

2

 

       下表将关系模式 R(ABC)分解成 p = {AB,AC},分解后的关系通过自然连接还原,会多出元组,丢失了信息,增加了噪声,并不是我们所期望的,这种分解称为“损失分解”:

A

B

C

 

A

B

 

A

C

 

A

B

C

1

1

4

 

1

1

 

1

4

 

1

1

4

1

2

3

 

1

2

 

1

3

 

1

1

3

 

 

 

 

 

 

 

 

 

 

1

2

4

 

 

 

 

 

 

 

 

 

 

1

2

3

 

  • 模式分解的优点
  1. 模式分解能消除数据冗余和操作异常。
  2. 在分解后的数据库中可以存储悬挂元组,存储泛关系中无法存储的信息。
  • 模式分解的缺点
  1. 分解以后,检索操作需要做笛卡尔积或连接操作,这将付出时间代价。
  2. 在有泛关系假设时,对数据库中关系进行自然连接时,可能产生寄生元组,即损失了信息。
  • 无损分解

       最简单的理解,分解后的关系自然连接后完全等于分解前的关系,则这个分解相对于 F 是无损的连接分解。

  • 无损分解的测试方法
  1. 键二维表,每一列对应一个属性,每一行对应一个分解模式。行为 i,列 为 j
  2. 对单元格进行初始化,若列属性存在于分解模式中,则标记为 aj,反之标记为 bij。
  3. 检查 F 中的每个 FD 在表格中是否成立。假设 X –> Y,若有两行的 X 值相同,而 Y 值不同,则将 Y 值修改为:aj 优先,若无,则选择最小的 bij。
  4. 最后,若表中有一行是全 a,那么 p 相对 F 是无损分解,否则是损失分解。

       举例:已知 R< U,F >,U = { A,B,C,D,E },F = { A → C,B → C,C → D,DE → C,CE → A },R 的一个分解为 R1(AD),R2(AB),R3(BE),R4(CDE),R5(AE),问这个分解是否具有无损连接性?

(1)建二维表,并对单元格值初始化

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b23

b24

b25

BE

b31

a2

b33

b34

a5

CDE

b41

b42

a3

a4

a5

AE

a1

b52

b53

b54

a5

(2)因为 A → C,而 1,2,5 行 A 列的值均为 a1,C 列的值不同,修改为 b13。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

b24

b25

BE

b31

a2

b33

b34

a5

CDE

b41

b42

a3

a4

a5

AE

a1

b52

b13

b54

a5

(3)因为 B → C,修改之。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

b24

b25

BE

b31

a2

b13

b34

a5

CDE

b41

b42

a3

a4

a5

AE

a1

b52

b13

b54

a5

(4)因为 C → D,修改之。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

a4

b25

BE

b31

a2

b13

a4

a5

CDE

b41

b42

a3

a4

a5

AE

a1

b52

b13

a4

a5

(5)因为 DE → C,修改之。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

a4

b25

BE

b31

a2

a3

a4

a5

CDE

b41

b42

a3

a4

a5

AE

a1

b52

a3

a4

a5

(6)因为 CE → A,修改之。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

a4

b25

BE

a1

a2

a3

a4

a5

CDE

a1

b42

a3

a4

a5

AE

a1

b52

a3

a4

a5

(7)最终,BE 行形成了全 a,这个分解是无损分解。

 

A

B

C

D

E

AD

a1

b12

b13

a4

b15

AB

a1

a2

b13

a4

b25

BE

a1

a2

a3

a4

a5

CDE

a1

b42

a3

a4

a5

AE

a1

b52

a3

a4

a5

 

  • 保持函数依赖的分解

       在分解过程中,要求模式分解的无损连接是必须的,只有无损连接分解才能保证任何一个关系能由它的那些投影进行自然连接得到恢复。同时,分解关系模式时还应保证关系模式的函数依赖集在分解后仍在数据库模式中保持不变,这就是保持函数依赖的问题。所有分解出的模式所满足的函数依赖的全体应当等价于原模式的函数依赖集。只有这样,才能确保整个数据库中数据的语义完整性不受破坏。

       例1. 设有关系模式 R(WNO,WS,WG)的属性分别代表员工的工号、工资级别、工资数目。如果规定,每个职工只有一个工资级别,一个工资级别只有一个工资数目,那么 R 上的 FD 有 F = {WNO –> WS,WS –> WG},此时,按下表进行分解的话(p = {R1,R2},其中 R1 = {WNO –> WS},R2 = {WNO –> WG}):

WNO

WS

 

WNO

WG

 

WNO

WS

 WG

W1

8级

 

W1

2000

 

W1

8级

2000

W2

6级

 

W2

1600

 

W2

6级

1600

W3

6级

 

W3

1400

 

W3

6级

1400

       可以验证,这个分解是无损分解。但从 R1,R2 这两个 FD 却推导不出 WS –> WG,因此分解 p 把 WS –> WG 丢失了,即 p 不保持函数依赖 F。一个无损分解不一定具有函数依赖保持性,反之,一个具有函数依赖保持性的分解也不一定是无损连接。

       例2. 设关系模式 R(ABC),p = {AB,AC}是 R 的一个分解。试分析分别在 (1)F = {A –> B};(2)F = {A –> C,B –> C};(3)F = {B –> A};(4)F = {C –> B,B –> A}这四种情况下,p 是否具有无损分解和保持 FD 的分解特性?(注:使用上面介绍过的无损分解测试方法来验证就非常简单了)

       解:

  1. 无损分解,保持了 FD。
  2. 无损分解,没有保持 FD 集,因为 B –> C 丢失了。
  3. 损失分解,保持了 FD 集。
  4. 损失分解,没有保持 FD 集,因为 C –> B 丢失了。

 

范式

       关系模式的好与坏,衡量的标准就是模式的范式(Normal Forms),简记为 NF。1NF 是基础,2NF 已成为历史,一般不再提及。数据库设计中最常用的是 3NF 和 BCNF。

  • 第一范式(1NF)

       关系模式 R 的每个关系 r 的属性值都是不可再分的原子值,那么称 R 是 第一范式。满足 1NF 的关系称为规范化的关系,关系数据库研究的都是规范化的关系,1NF 是关系模式应具备的最起码的条件。

  • 第二范式(2NF)

       如果关系模式 R 为第一范式,并且 R 中每一个非主属性完全函数依赖于 R 的某个候选键,则称为 第二范式非主属性 指关系模式 R 中不包含在任何“键”中的属性。设有函数依赖 W –> A,若存在 X ? W,有 X –> A 成立,那么称 W –> A 是局部依赖,否则就称 W –> A 是完全依赖。

       例如,有关系模式 R(S#,C#,SCORE,T#,TITLE),(S#,C#)是 R 的候选键,R 上有两个 FD:(S#,C#)-> (T#,TITLE),C# -> (T#,TITLE),因此前一个是局部依赖,R 不是 2NF 模式。此时,R 的关系就会出现冗余和异常现象,如果一门课程有 100 个学生选修,关系中就会出现 100 个元组重复着 100 次的教师工号和职称。

  • 第三范式(3NF)

       如果关系模式 R 是第二范式,且每个非主属性都不传递依赖于 R 的候选键,则称为 第三范式。传递依赖:在关系模式中,如果 X –> Y,Y –> A,且 Y 不决定 X and A 不属于 Y,那么称 X –> A 是传递依赖。说白了,就是要求一个数据库的表中不包含已在其它表中包含的非主关键字信息。如上面提到的关系模式分解为 R1(S#,C#,SCORE)、R2(C#,T#)、R3(T#,TITLE),则符合 3NF。

  • BCNF

       3NF 的改进形式,消去主属性对键的传递函数依赖。

  • 分解成 3NF 模式集的合成算法
  1. 对于关系模式 R 和 R 上成立的 FD 集 F,先求出 F 的最小依赖集,然后把其中那些左部相同的 FD 用合并性括起来。
  2. 对最小依赖集中,每个 FD X –> Y 都构成一个模式 XY。
  3. 在构成的模式集中,如果每个模式都不包含 R 的候选键,那么把候选键作为一个模式放入模式集中。

       例. 设关系模式 R(ABCDE),R 的最小依赖集为 {A –> B,C –> D},从依赖集可知 R 的候选键为 ACE。根据最小依赖集,可知 p = {AB,CD},然后再加入由候选键组成的 ACE,因此,最终结果 p = {AB,CD,ACE}是一个 3NF 模式集且 p 相对于该依赖集是无损分解且保持 FD。

  • 模式设计的方法

       关系模式 R 相对于函数依赖集 F 分解成数据库模式 p = {R1,R2…,Rn},一般应具有以下特性

  1. 每个关系模式 Ri 应具有某种范式性质(3NF 或 BCNF)
  2. 无损分解。
  3. 保持函数依赖性。
  4. 最小性,即 p 中模式个数应最少且模式中属性总数应最少。

 

多值依赖和第四范式

  • 多值依赖

       设 U 是关系模式 R 的属性集,X 和 Y 是 U 的子集,Z = U - X - Y,小写的 xyz 表示属性集 XYZ 的值。对于 R 的关系 r,在 r 中存在元组(x,y1,z1)和(x,y2,z2)时,也存在元组(x,y2,z1)和(x,y1,z2)时,则称为多值依赖 (MVD)X –>-> Y 在模式 R 上成立。

       关系模式 R(COURSE,STUDENT,PRECOURSE)表示课程、学生、这门课的前置课程。这个模式表达了两件事:一门课程有很多学生选修,一门课程有很多前置课程,都是 1:N 的联系,且两个联系是独立的。非形式的说,只要两个独立的 1:N 联系出现在一个关系中,就会出现多值依赖。模式 R 的属性值间一对多联系也可用 MVD 表示:COURSE –>-> STUDENT 和 COURSE –>-> PRECOURSE

  • FD 和 MVD 的推理规则
  1. A1(FD 的自反性):若 Y ? X,则 X –> Y。
  2. A2(FD 的增广性):若 X –> Y,且 Z ? U,则 XZ –> YZ。
  3. A3(FD 的传递性):若 X –> Y,Y –> Z,则 X –> Z。
  4. M1(MVD 的补规则):若 X –>-> Y,则 X –>-> (U - XY)。
  5. M2(MVD 的补规则):若 X –>-> Y,且 V ? W ? U,则 WX –>-> VY。
  6. M3(MVD 的传递性):若 X –>-> Y,Y –>-> Z,则 X –>-> (Z – Y)。
  7. M4(MVD 的并规则):若 X –>-> Y,X –>-> Z,则 X –>-> YZ。
  8. M5(MVD 的交规则):若 X –>-> Y,X –>-> Z,则 X –>-> Y 交 Z。
  9. M6(MVD 的差规则):若 X –>-> Y,X –>-> Z,则 X –>-> Y - Z,X –>-> Z - Y。
  10. M7(MVD 的伪传递):若 X –>-> Y,WY –>-> Z,则 WX –>->  Z - WY。
  11. M8(混合伪传递):若 X –>-> Y,XY –>-> Z,则 X –>  Z - Y。
  12. FM1(FD 到 MVD 的复制性):若 X –> Y,则 X –>-> Y。
  • 应用举例

       例. 设关系模式 R(A,B,C,D)在 R 上有如下五个相应的 FD 集及分解,回答下列问题,(1)确定 R 的关键码(2)是否无损分解?(3)是否保持 FD 集?(4)确定 p 中每一模式的范式级别。

       提示1:求 R 的关键码或者候选键,应对所有子集,注意计算属性集的闭包,才能得到表示整个属性集的关键码或候选键!

       提示2:是否无损分解需采用无损分解测试方法。

       提示3:是否保持了函数依赖性,首先要分解 FD 集 F 的函数依赖,再根据分解模式去一一匹配。如 A –> CD 即 A –> C 和 A –> D。

       提示4:关于范式,1NF 属性值达到了原子值;2NF 消除了次要属性对键的局部函数依赖;3NF 消除了次要属性对键的传递函数依赖;BCNF 消除了每一属性对键的传递函数依赖;4NF 消除了非平凡非 FDMVD

  • F = {B –> C,D –> A},p = {BC,AD}

       答:R 的关键码是 BD;p 不是无损分解;p 保持了 FD 集;p 中两个模式都达到 BCNF 级别。

  • F = {AB –> C,C –> A,C –> D},p = {ACD,BC}

       答:R 的关键码有两个:AB 和 BC;p 是无损分解;p 没有保持 FD 集,丢失了 AB –> C;p 中两个模式都达到 BCNF 级别。

  • F = {A –> BC,C –> AD},p = {ABC,AD}

       答:R 的关键码为 A 或 C;p 是无损分解;模式 ABC(F)={A –> BC,C –> A},模式 AD(F)={A –> D},所以 p 保持了 FD 集;模式 ABC 中的属性全是主属性,但有传递依赖(A –> BC,BC –> A),因此 ABC 是 3NF,但不是 BCNF,而模式 AD 是 BCNF 级别。

  • F = {A –> B,B –> C,C –> D},p = {AB,ACD}

       答:R 的关键码是 A;p 是无损分解;p 不保持了 FD 集,B –> C 丢失了;模式 AB 是 BCNF 级别,模式 ACD 只达到了 2NF 级别(D 依赖于 C 也依赖于 A,而 C 又依赖于 A,这里有冗余,3NF 不允许存在 关键码 –> 非主要属性1 –> 非主要属性2 )。

  • F = {A –> B,B –> C,C –> D},p = {AB,AD,CD}

       答:R 的关键码是 A;p 不是无损分解;p 不保持了 FD 集,B –> C 丢失了;p 中每个模式均为 BCNF 级别。

关系模式设计理论 - 数据库系统原理

标签:属性   条件   第一范式   不一致   这一   解决   规范化   推导   元组   

原文地址:http://www.cnblogs.com/SkySoot/p/6247030.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!