数据库期末复习

第一章 绪论

数据库的基本概念

数据:描述事物的符号记录

数据库:存放数据的仓库。(长期存储在计算机内、有组织的、可共享的大量数据的集合)

数据库管理系统:是一组程序的集合,将数据存储道数据库,并可以修改和获取数据库中的数据

数据库管理系统的主要功能

  1. 数据定义功能
  2. 数据组织、存储和管理
  3. 数据操纵功能
  4. 数据库的事物管理和运行管理
  5. 数据库的建立和维护功能
  6. 其他功能

数据库系统:数据库系统是由数据库、数据库管理系统、应用程序和数据库管理员(DBA)组成的存储、管理、处理和维护数据的系统

数据管理三个阶段的比较

人工管理 文件系统 数据库系统
谁管理数据 程序员 操作系统提供存取方法 系统集中管理
面向谁 特定应用 基本上是特定用户 面向系统
共享性 不能 共享很弱 充分共享
数据独立性 没有 一定的物理独立性 较高的独立性

数据模型

数据模型的三要素:数据结构、数据操作、数据的完整性约束

数据库中常用的逻辑数据模型

  1. 层次模型
  2. 网状模型
  3. 关系模型
  4. 面向对象模型

数据库系统的结构

三级模式结构:

  1. 内模式:也称存储模式,是数据物理结构和存储方式的描述。一个数据库只有一个内模式

  2. 模式:也称概念模式或逻辑模式,是数据库中全体数据的逻辑结构和特征的描述

    简单来说:模式就是确定数据库中有哪些表,以及这些表有哪些字段,各字段类型、长度是什么,各数据之间有什么联系等等,不涉及到具体的数据

  3. 外模式:也称子模式或者用户模式,是数据库用户能够看见和使用的局数据的逻辑结构和特征描述

    简单来说:可以粗略的将外模式理解为“视图(view)”。(视图是外模式的一种实现方式)

两层映像:

  1. 外模式/模式映像:定义外模式和模式之间的映射关系。一个模式可以有多个外模式,每个外模式都有一个“外模式/模式映像”

    作用:模式改变时,只需修改映像,无序改变外模式。从而应用程序不必修改,保证了程序和数据的逻辑独立性。

    举例:

    # 学生表
    Student(Sno,Sname,Sage,Ssex,...)
    # 基于学生表创建的视图,用于查询学生的性别
    create view sex_v as select Sno,Ssex from Student;
    # 视图中有两个字段Sno和Ssex
    
    # 假设我们编写了一个程序,某功能用于获取学生的学号和性别,该功能基于视图sex_v就行查询。
    # 程序中查询的字段名为Sno和Ssex。
    
    # 假设现在需要对Student表进行调整,需要将Ssex改名为Sgender
    # 只需修改模式与外模式之间的映射,以本例子来说,就是修改sex_v视图
    create view sex_v as select Sno,Sgender as Ssex from Student;
    # 视图修改后,虽然Student表进行了调整,但是视图中两个字段仍然为Sno和Ssex
    # 所以程序中,查询学生学号和性别的功能的代码仍然无需改变
    
    # 可以预见,如果我们程序中的所有对表的操作都是基于视图,
    # 那么无论数据库怎么改变,只需在数据库层面处理好基本表与视图的映射关系,
    # 就无需再去变更程序中的代码,实现了数据与程序的逻辑独立性
    # 当然,这只是理想情况,实际项目中应根据实际业务进行调整。
    
  2. 内模式/模式映像:定义数据库的全局逻辑结构与存储结构之间的对应关系。一个数据库只有一个内模式,所以也只有一个内模式/模式映像。

    作用:与外模式/模式类似,当数据库的存储结构改变时,可通过修改映像,使数据库的逻辑结构(模式)保持不变。保证了程序和数据的物理独立性。

第二章 关系数据库

关系模型的基本概念

关系:关系模型中用于描述数据的主要结构

属性:关系中的每列对应一个属性,也叫做关系的字段

:一组具有相同数据类型的值的集合

分量:元组中的属性值

码(候选码)

  • 码(候选码) :也叫做键或关键字。它是关系型中能够唯一标识一个元组的属性或属性组
  • 主码:从候选码中选出一个来作为主码,也叫做主键

主属性:包含再任意候选码中的属性

非主属性:不包含再任意候选码码中的属性

全码:候选码由关系表的所有属性组成

关系模式:关系数据库中,关系模式是型,它确定关系由哪些属性构成,即关系的逻辑结构,而关系是值

关系数据库模式:关系数据库的型称为关系数据库模式

注意:对于码、主码、全码都需要满足唯一性和最小性

  • 唯一性:码的取值必须能够唯一标识表中的每一行
  • 最小性:码中不能包含多余的属性。如果去掉任意一个属性,剩下的属性组就不能唯一标识行,则称该码是最小化的

关系的性质

关系应该满足如下性质:

  1. 列是同质的,即同一列的数据类型必须相同
  2. 每列必须是不可再分的数据项(不允许表嵌套表)
  3. 元组不重复,即不能有相同的行
  4. 元组无序性
  5. 属性无序性
  6. 属性不同名

关系模型的形式化定义

关系的形式化定义:D1×D2×⋯×Dn的子集叫做再域D1,D2,⋯,Dn上的关系,表示为R(D1,D2,...,Dn)

其中R为关系名,n为关系的目或度。

关系模式的形式化定义:R(U,D,DOM,F)

其中,R为关系名,U为该关系的所有属性,D为U中属性所来自的域,DOM为属性像域的映射,F为属性减的数据依赖。

关系操作

常用的关系操作:

  • 查询:选择、投影、连接、除、并、交、差
  • 数据更新:插入、删除、修改
  • 查询的表达能力是其中最主要的部分
  • 选择、投影、并、差、笛卡尔积是5种基本操作

关系操作的特点:集合操作方式,操作的对象和结果都是集合,一次一集合的方式

SQL是一种高度非过程化语言,SQL语句分为以下四类:

类型 描述 关键字
DDL 数据库定义语言,用来定义和管理数据库或者数据表 create, alter, drop
DML 数据库操纵语言,用来操作数据 insert, update, delete
DQL 数据库查询语言,用来查询数据 select
DCL 数据库控制语言,权限控制 grant, revoke, commit, rollback

关系模型的完整性

关系模型中有三类完整性约束:实体完整性、参照完整性、用户自定义完整性

其中实体完整性和参照完整性必须满足,被称为关系的两个不变性

外码:以学生表和学院表为例(学生表中学院编号为外码,学院表中学院编号为主码)

  • 学生表中的学院编号称为学生表的外码(外键)
  • 学生表为参照关系,学院表为被参照关系

主码和外码之间的参照完整性规则:同样以学生表和学院表为例

  • 学生表中的学院编号,要么为空
  • 要么就等于学院表中的某个学院编号
  • 也就是说不能存在根据学生表中的学院编号取学院表中查找,找不到对应学院的情况

用户自定义完整性:其实就是创建表时规定的字段的属性,比如主键、外键、是否为空、唯一性等等。

第三章 SQL

SQL概述

SQL:结构化查询语言,是关系数据库的标准语言,是一个通用的、功能极强的关系数据库语言

  • SQL提供数据的定义、查询、更新和控制等功能
  • SQL不是一个应用程序开发语言
  • SQL不是一个DBMS

基本表:独立存在的表,一个关系对应一个基本表

视图:是一个虚拟的表,从一个或几个基本表导出的表,它本身不独立存在于数据库中,其数据来自于基本表

模式与基本表:每个基本表都属于一个模式,一个模式包含多个基本表

数据类型

数据类型 含义
CHAR(n) 长度为n的定长字符串
VARCHAR(n) 最大长度为n的变长字符串
INT 长整数(也可以写作INTEGER)
SMALLINT 短整数
NUMERIC(p,d) 定点数,由p位数字(不包括符号、小数点)组成,小数后面有d位数字。(DECIMAL类型与改了类型类似。)
REAL 取决于机器精度的浮点数
Double Precision 取决于机器精度的双精度浮点数
FLOAT(n) 浮点数,精度至少为n位数字
DATE 日期,包含年、月、日,格式为YYYY-MM-DD
TIME 时间,包含一日的时、分、秒,格式为HH:MM:SS

索引

谁可以建立索引:DBA 或 表的属主(即建立表的人)

DBMS一般会自动建立以下列上的索引

  • PRIMARY KEY
  • UNIQUE

谁维护索引:DBMS自动完成
使用索引:DBMS自动选择是否使用索引以及使用哪些索引

索引的分类

  • 聚集索引:按照索引的字段排列记录,并且依照排好的顺序将记录存储在表中
  • 非聚集索引:按照索引的字段排列记录,但是排列的结果不会存储在表中,而是另外存储

唯一索引:表中每一个索引值只对应唯一的数据记录

  • 唯一索引通常用于主键上
  • 当表中有被设置为unique字段时,会在该字段上自动建立一个非聚集的唯一索引
  • 当表中有主键字段时,会在主键上自动建立一个聚集索引

复合索引:将两个或多个字段组合起来建立的索引,单独的字段允许有重复的值

RDBMS中索引一般采用B+树、HASH索引来实现

  • B+树索引具有动态平衡的优点
  • HASH索引具有查找速度快的特点

查询

select语句的一般格式

SELECT [ALL|DISTINCT]  
   <目标列表达式> [别名] [,<目标列表达式> [别名]] …
 FROM <表名或视图名> [别名] 
      [,<表名或视图名> [别名]] …
 [WHERE <条件表达式>]
 [GROUP BY <列名1>
 [HAVING <条件表达式>]]
 [ORDER BY <列名2> [ASC|DESC] 

image

字符匹配like

基本格式:[NOT]LIKE '<匹配串>',[ESCAPE '<换码字符>',]

匹配串可以是完整的字符串,也可以含有通配符:

  • %​:匹配0个或多个任意字符

  • _​:匹配一个任意字符

    • 注意:数据库字符集为ASCII时一个汉字需要两个_​,当字符集为GBK时只需要一个_​。

换码字符:将通配符转换伟普通字符

当要匹配的字符串中存在通配符时,

-- 使用换码字符\,来将字符串中的_转换伟普通字符
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';

SQL语句

操作表

创建表

-- 3、创建选课表SC
create table SC(
    Sno char(11),
    Cno char(5),
    Grade decimal(3,1),
    primary key (Sno,Cno),
    constraint fk_SC_Student_Sno foreign key (Sno) references Student(Sno),
    constraint fk_SC_Course_Cno foreign key (Cno) references Course(Cno)
)charset=utf8mb4;

修改表

-- 4、向Student表增加“入学时间”列,其数据类型为日期型
alter table Student
add column start_time date;		-- 删除字段的话,将add修改为drop
-- 删除外键约束
alter table Course
drop foreign key fk_Course_self_Cpno;
-- 添加外键约束
alter table Course
add constraint fk_Course_self_Cpno foreign key (Cpno) references Course(Cno);

删除表

-- 5、删除Student表
drop table Student;

将一个表的查询结果插入到另一个表

insert into dept_avg_age(dept,avg_age)
select Sdept,avg(Sage)
from Student
group by Sdept;

操作记录

-- 11、将学生20200510103的年龄改为22岁
update Student set Sage=22
where Sno='20200510103';

-- 12、将所有学生的年龄增加 1岁。
update Student set Sage=Sage+1;

-- 13、将计算机科学系全体学生的成绩置零。
update SC set Grade=0
where Sno in (
    select Sno
    from Student
    where Sdept='计算机系'
    );

-- 14、删除学号为20200510109的学生记录。
delete from Student where Sno='20200510109';

-- 15、删除所有的学生选课记录。
delete from SC;

-- 16、删除计算机科学系所有学生的选课记录。
delete from SC
where Sno in (
    select Sno
    from Student
    where Sdept='计算机系'
    );

简单查询

-- 19、从Student表中找出漏填了数据的学生信息
select *
from Student
where Ssex is null or
      Sage is null or
      Sdept is null;

-- 23、查全体学生的姓名及其出生年份
select Sname,(2025-Sage) as birth
from Student;

-- 24、查询全体学生的姓名、出生年份和所在的院系,要求用小写字母表示系名
select Sname,(2025-Sage) as birth,lower(Sdept) as Sdept
from Student;

-- 25、查询选修了课程的学生学号
select Sno
from SC;

-- 29、查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄
select Sname,Sdept,Sage
from Student
where Sage between 20 and 23;

-- 30、查询年龄不在20~23岁之间的学生姓名、系别和年龄
select Sname,Sdept,Sage
from Student
where Sage not between 20 and 23;

-- 31、查询计算机科学系(CS)、物理系(PS)和信息系(IS)学生的姓名和性别
select Sname,Ssex
from Student
where Sdept in ('计算机系','物理系','信息系');

-- 32、查询既不是计算机科学系、数学系,也不是信息系的学生的姓名和性别
select Sname,Ssex
from Student
where Sdept not in ('计算机系','数学系','信息系');

-- 40、某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号
select Sno,Cno
from SC
where Grade is null;

like

-- 34、查询所有姓刘学生的姓名、学号和性别
select Sname,Sno,Ssex
from Student
where Sname like '刘%';

-- 35、查询姓"欧阳"且全名为三个汉字的学生的姓名
select Sname
from Student
where Sname like '欧阳_';

-- 36、查询名字中第2个字为"阳"字的学生的姓名和学号
select Sname,Sno
from Student
where Sname like '_阳%';

-- 37、查询所有不姓刘的学生姓名、学号和性别
select Sname,Sno,Ssex
from Student
where Sname not like '刘%';


-- 38、查询DB_Design课程的课程号和学分
-- DataGrip启用了启用了 NO_BACKSLASH_ESCAPES 模式,默认就是用反斜杠转义
-- 可以省略escape(使用esacpe '\'会报错),或者采用其他字符作为转义字符
select Cno,Ccredit
from Course
where Cname like 'DB!_Design' escape '!';

-- 39、查询以"DB_"开头,且倒数第3个字符为i的课程的详细情况
select *
from Course
where Cname like 'DB!_%i__' escape '!';

排序

-- 44、查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列
select Sno,Grade
from SC
where Cno='3'
order by Grade desc;

-- 45、查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列
select *
from Student
order by Sdept,Sage desc;

分组、聚合函数

-- 47、查询选修了课程的学生人数
select count(distinct Sno) from SC;

-- 48、计算1号课程的学生平均成绩
select avg(Grade)
from SC
where Cno='1';

-- 50、查询学生20200510102选修课程的总学分数
select sum(Grade)
from SC
where Sno='20200510102';

-- 51、求各个课程号及相应的选课人数
select Cno,count(Sno) as num
from SC
group by Cno;

-- 52、查询选修了3门以上课程的学生学号
select Sno
from SC
group by Sno
having count(Cno) > 3;

-- 53、查询平均成绩大于等于90分的学生学号和平均成绩
select Sno,avg(Grade)
from SC
group by Sno
having avg(Grade) >= 90;

联合查询、子查询

涉及到多表查询的,有时可以通过多种方式实现,可以用join或者子查询等等,哪种方便用哪种。

-- 54、查询每个学生及其选修课程的情况
select S.*,SC.Cno,SC.Grade
from Student as S left join SC on S.Sno = SC.Sno;

-- 55、查询选修2号课程且成绩在90分以上的所有学生的学号和姓名
select S.Sno,S.Sname
from Student as S,SC
where S.Sno=SC.Sno and
      Cno='2' and
      Grade>90;

-- 56、查询每个学生的学号、姓名、选修的课程名及成绩
-- 因为说的是“每个”学生,所以需要使用左外链接
select S.Sno,Sname,Cname,Grade
from Student as S
    left join SC on S.Sno = SC.Sno
    left join Course on SC.Cno=Course.Cno;


-- 57、查询与“张爽”在同一个系学习的学生
select Sno,Sname
from Student
where Sdept = (
    select Sdept
    from Student
    where Sname='张爽'
    );

-- 58、查询选修了课程名为“信息系统”的学生学号和姓名
select S.Sno,Sname
from Student as S
    join SC on S.Sno = SC.Sno
    join Course C on SC.Cno = C.Cno
where Cname='信息系统';

-- 59、找出每个学生超过他选修课程平均成绩的课程号
======================== 注意 =============================
select SC.Sno,Cno
from SC
join (
    select Sno,avg(Grade) as AvgGrade
    from SC
    where Grade is not null -- 排除缺考的课程
    group by Sno
) as StuAvg on SC.Sno = StuAvg.Sno
where SC.Grade > StuAvg.AvgGrade;

-- 60、查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
select Sname,Sage
from Student
where Sdept != '计算机系' and
      Sage < any (
          select Sage
          from Student
          where Sdept='计算机系'
      );
-- 注意“任意一个”,与“所有”的区别
-- 61、查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄
select Sname,Sage
from Student
where Sdept!='计算机系' and
      Sage < all (
          select Sage
          from Student
          where Sdept='计算机系'
      );

-- 62、查询所有选修了1号课程的学生姓名
select Sname
from Student as S,SC
where S.Sno=SC.Sno and
      Cno='1';
-- 或者
select Sname
from Student
where Sno in (
    select Sno
    from SC
    where Cno='1'
);

-- 63、查询没有选修1号课程的学生姓名
select Sname
from Student
where Sno not in (
    select Sno
    from SC
    where Cno='1'
    );

-- 65、查询选修了全部课程的学生姓名
-- 假设一名学生不能重复选修同一门课程
select Sname
from Student
where Sno in (
    select Sno
    from SC
    group by Sno
    having count(Cno)>(
        select count(*) from Course
        )
    );

-- 66、查询至少选修了学生20200510103选修的全部课程的学生号码
-- 1、过滤出与03学生选修课程相同的记录
-- 2、对过滤出的记录按学号分组,计算出每个学生选修的课程数。
-- 只要某学生课程数等于03学生选修的课程数,则说明该学生至少选修了03学生选修的全部课程。
select Sno
from SC
where Cno in (
    select Cno  -- 1、查询出03号学生选修的课程
    from SC
    where Sno='20200510103'
    )
group by Sno
having count(Cno) >= (
    select count(*) -- 2、03号学生选修的课程数量
    from SC
    where Sno='20200510103'
    );

并交差

把集合运算转换伟对应的逻辑表达式,作为where的条件即可

-- 69、查询计算机科学系的学生与年龄不大于19岁的学生的交集
-- 注意,mysql只支持union(并)而不支持intersect(交)和except(差)
select Student.*
from Student
where Sdept='计算机系' and Sage<19;

-- 72、查询计算机科学系的学生与年龄不大于19岁的学生的差集(A-B:A中有,且B中没有)
select *
from Student
where Sdept='计算机系' and Sage>19;

视图

只需掌握create view 视图名称 as 查询语句​,根据题目编写对应的查询语句即可

-- 77、建立信息系学生的视图
create view V77 as
select *
from Student
where Sdept='信息系';

-- 78、建立信息系学生的视图,并要求进行修改和插入操作时仍需保证该视图只有信息系的学生
create view V78 as
select *
from Student
where Sdept='信息系'
with check option;

-- 84、在信息系学生的视图中找出年龄小于20岁的学生
select *
from V77
where Sage<20;

第六章 关系数据理论

不好的关系模式会存在哪些问题?

  1. 插入异常
  2. 删除异常
  3. 更新异常
  4. 数据冗余大

函数依赖

X函数决定Y(或Y函数依赖于X):X能够唯一确定Y。记作X->Y

非平凡函数依赖:X->Y,但Y不包含于X。

平凡函数依赖:X->Y,同时Y包含于X。平凡函数依赖必然成立。

完全函数依赖:X->Y,且满足最小性(X的任何一个真子集都无法确定Y)。记作$\mathrm{X}\overset{F}{\operatorname*{\rightarrow}}\mathrm{Y}$​

非完全函数依赖:X->Y,不满足最小性。记作$\mathrm{X}\overset{P}{\operatorname*{\rightarrow}}\mathrm{Y}$

传递函数依赖:X->Y(Y⊈X),X-/->Y,Y->Z(Z⊈Y)

范式

第一范式(1NF) :所有属性都是不可再分的基本数据项

  • 晋升到下一范式的条件:消除非主属性对码的部分函数依赖

第二范式(2NF) :每个非主属性都完全函数依赖于R的码

  • 反例:SC(课程号,学号,课程名,成绩,),存在课程名对码(学号,课程号)的部分函数依赖
  • 推论:如果关系R所有的码中只包含一个属性且属于1NF,则R必属于2NF
  • 晋升条件:消除非主属性对码的部分传递依赖

第三范式(3NF) :每个非主属性既不部分依赖于码,也不传递依赖于码

  • 反例:SC(课程号,学号,课程名,成绩,)存在学号->课程号->课程名​的传递函数依赖(非主属性课程名,对主属性学号的传递依赖)
  • 推论:不存在非主属性的关系模式(全码)一定属于3NF
  • 晋升条件:消除主属性主属性对码的部分依赖和传递依赖

BC范式(BCNF) :在3NF的基础上消除主属性对码的部分依赖和传递依赖

BCNF的三个性质

  1. 所有非主属性都完全函数依赖于每个候选码
  2. 所有主属性都完全函数依赖于每个不包含于它的候选码
  3. 没有任何属性完全函数依赖于非码的任何一组属性

解题思路:画出函数依赖图,对图进行切割从组

注:在函数依赖范畴内,BCNF已经实现了模式的彻底分解,达到了最高的规范化程度。但并不是规范化程度越高,模式越好。

第七章 数据库设计

数据库的设计过程

  1. 需求分析
  2. 概念结构设计
  3. 逻辑结构设计
  4. 物理结构设计
  5. 数据库实施
  6. 数据库运行维护

数据库各级模式的形成

  1. 需求分析阶段:综合各个用户的应用需求(现实世界的需求)。
  2. 概念设计阶段:概念模式(信息世界模型),用E-R图来描述。
  3. 逻辑设计阶段:逻辑模式、外模式。
  4. 物理设计阶段:内模式。

第十章 数据库安全性

计算机安全性:为计算机系统建立和采取的各种安全保护措施,以保护计算机系统中的硬件、软件及数据,防止其因偶然或恶意的原因使系统遭到破坏,数据遭到更改或泄露等。

三类安全性问题:技术安全类,管理安全类,政策法律类

安全级别(4组7个等级,安全性依次增高):D、C1、C2、B1、B2、B3、A1

数据库安全性控制的常用方法

  1. 用户标识和鉴定(用户身份鉴别)
  2. 存取控制技术
  3. 视图技术
  4. 审计技术
  5. 密码存储(数据加密)

补充(数据库完整性)

数据库完整性是为了保证数据库中存储的数据是正确的。

关系数据库管理系统完整性实现的机制

  • 完整性约束定义机制
  • 完整性检查机制
  • 违背完整性约束时关系数据库管理系统应采取的动作

十一章 数据库恢复技术

事务(Transaction) :是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。

事物是恢复并发控制基本单位

事物的性质:ACID性

  • 原子性(Atomicity):事物执行时的不可分割性,要么彻底做完要么不做。
  • 一致性(Consistency):事务对数据库的作用应使数据库从一个一致状态到另一个一致状态
  • 隔离性(Isolation):多事务并发执行,应像各事务独立执行时一样,不能互相干扰
  • 持久性(Durability):事务一但提交,不论执行任何操作或发生故障,都不应对事物的结果有任何影响

数据库系统的故障种类

  • 事物内部故障
  • 系统范围内的故障(软故障)
  • 介质故障(硬故障)
  • 计算机病毒

恢复策略

数据库恢复的基本原理:冗余

数据库恢复的机制(两步):

  1. 建立冗余数据
  2. 利用冗余数据实施数据库恢复

恢复中最经常使用的技术:

  • 数据库转储
  • 登记日志文件

利用日志文件进行恢复

基本策略:

  • 对于尚未提交的事务,执行撤消处理(UNDO)
  • 对于已经提交的事务,执行重做处理(REDO)

基本方法:扫描日志文件,确定所有已开始但尚未提交的事务,对它们需UNDO),再确定所有已提交的事务(对它们需REDO)

十二章 并发控制

封锁的类型:

  1. 排它锁(X锁) :独占对象,不允许其他事务进行读写。
  2. 共享锁(S锁) :也就是共享读。对对象加S锁后,可以对对象读取,但不能写入。其他事务也能对该对象加S锁。

封锁协议:在运用X锁和S锁对数据对象加锁时,对何时申请X锁或S锁、持锁时间、何时释放等的一些约定。

根据上锁的类型和释放锁的时机,分为三种情况:

  1. 1级封锁协议:在修改对象之前,必须加X锁,直到事务结束才释放。但对读操作无限制,无需加锁也能读

    • 解决的问题:丢失修改。多个事务在同时修改同一个对象时,只会保留最后提交的事务的修改,其他事务的修改被覆盖。
    • 存在的问题:脏读。若某事物对对象修改后又回滚,而在这期间另一个事务读取了该对象被修改后、回滚前的数据,产生了脏读。
  2. 2级封锁协议:1级封锁协议+在读取对象之前必须加S锁,读完立即释放S锁

    • 解决的问题:解决脏读。当前事物在正在修改对象(加X锁),另一个事务想要读取该对象就需要申请S锁,由于X锁和S锁不能共存,所以另一个事务只能在等待当前事务将X锁释放后(事务结束)才能申请到S锁,从而读取数据,
    • 存在的问题:不可重复读。假设当前事务会读取两次对象,由于S锁在读完后立即释放,在这期间,该对象可能会被其他事务给修改,从而导致了当前事务读取同时对象两次,两次结果不一致。
  3. 3级封锁协议:1级封锁协议+在读取对象之前必须加S锁,事务结束才释放

    • 解决的问题:解决不可重复读。S锁持续到事务结束,保证对该对象在事务结束前都不会被其他事务修改。
    • 存在的问题:幻读。

总结:

协议 写操作锁(X 锁) 读操作锁(S 锁) 解决的问题 仍存在的问题
一级 事务结束释放 无需加锁 丢失修改 脏读、不可重复读、幻读
二级 事务结束释放 读完立即释放 丢失修改、脏读 不可重复读、幻读
三级 事务结束释放 事务结束释放 丢失修改、脏读、不可重复读 幻读