数据:描述事物的符号记录。
数据库:概括地讲,数据库数据具有永久存储、有组织和可共享的三个基本特点。
数据库管理系统:是位于⽤户和操作系统之间的⼀层数据管理软件,和操作系统⼀样是计算机的基础软件。
数据库系统:是由数据库、数据库管理系统(及其应⽤开发⼯具)、应⽤程序和数据库管理员(DBA)组成的存储、管理、处理和维护数据的系统。
⼈⼯管理阶段:数据不保存、不共享,不具有独⽴性。
⽂件系统阶段:可保存,但共享性差,冗余度⼤,独⽴性差。
数据库管理系统:数据库系统的出现使信息系统从以 加⼯数据的程序为中⼼ 转向围绕 共享的数据库 为中⼼的新阶段
实现整体数据的结构化
数据的共享性⾼、冗余度低且易扩充:数据共享可以⼤⼤减少数据冗余,节约存储空间
数据独⽴性⾼:
两类数据模型:概念模型+逻辑模型和物理模型
(⼈们⾸先将现实世界抽象为信息世界,然后将信息世界转还为机器世界)
概念模型
也称信息模型,它是按⽤户观点来对数据和信息建模,主要⽤于数据库设计。
基本概念:
实体:客观存在并可相互区别的事物。 ⼈
属性:实体所具有的某⼀特性。 ⼈的⿐⼦ 嘴巴
码:唯⼀标识实体的属性。 学号
实体型:⽤实体名及其属性集合来抽象和刻画同类实体。 含有⿐⼦和嘴巴的⼈
实体集:同⼀类型实体的集合。 学校
联系:实体之间的联系通常是指不同实体集之间的联系。实体之间的联系有⼀对⼀、⼀对多和多对多等多种联系。
联系:
常⽤的数据模型:层次模型,⽹状模型,关系模型,
⾯向对象数据模型,对象关系数据模型,半结构化数据模型。
层次模型:
模式是相对稳定的,实例是相对变动的。
三级模式结构:外模式+模式+内模式
外模式:也称⼦模式或⽤户模式,它是数据库⽤户(包括应⽤程序员和最终⽤户)能够看⻅和使⽤的局部数据的逻辑结构和特征的描述,是数据库⽤户的数据视图,是与某⼀应⽤有关的数据的逻辑表示。
模式:也称为逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有⽤户的公共数据
内模式:也称存储模式,⼀个数据库只有⼀个内模式。它是数据物理结构和存储⽅式的描述,是数据在数据库内部的组织⽅式。
外模式/模式映像:当模式改变时,由数据库管理员对各个外模式/模式映像作相应改变, 可以使外模式保持不变。应⽤程序不必修改。保证了数据与程序的逻辑独⽴性。
模式/内模式映像:当数据库的存储结构改变时,有数据库管理员对模式/内模式作相应改变, 可以使模式保持不变,从⽽应⽤程序也不⽤改变。保证了数据与程序的物理独⽴性。
数据与程序之间的独⽴性使得数据的定义和描述可以从应⽤程序中分离出去。
另外,由于数据的存取由数据库管理系统管理,从⽽简化了应⽤程序的编制,⼤⼤减少了应⽤程序的维护和修改。
硬件平台及数据库:⾜够⼤内存、磁盘或磁盘阵列等设备,较⾼的通道能⼒以提⾼数据的传
软件:数据库管理系统,⽀持数据库管理系统运⾏的操作系统,具有与数据库接⼝的⾼级语⾔及其编译系统,以数据库管理系统为核⼼的应⽤开发⼯具,为特定应⽤环境开发的数据库应⽤系统。
⼈员:开发、管理和使⽤数据库的⼈员主要包括数据库管理员、系统分析员和数据库设计⼈员、应⽤程序员和最终⽤户。
R(U,D,DOM,F)
R:关系名
U:所有属性名
D:属性来⾃哪些域
DOM:属性和域的映射
F:属性间的依赖关系
关系代数运算:5种基本运算:并,差,笛卡⼉积,选择,投影及交,连接,除。
选择:选出满足关系的行
悬浮元组(Dangling tuple):没用过的行
两个关 系R和S在做自然连接时,关系R中某些元组有可能在S中不存在公共属性上值相等 的元组,
从⽽造 成R中这些元组在操作时被舍弃了,这些 被舍弃的 元组 称 为悬 浮元组。
外连接(Outer Join):左+右
左外连接(LEFT OUTER JOIN或LEFT JOIN):将R里面没用的行写到右边,然后剩下的值填Null
右外连接(RIGHT OUTER JOIN或RIGHT JOIN):将S里面没用的行写到右边,然后剩下的值填Null
实体完整性
参照完整性
用户定义完整性
SQL是Structured Query Language的缩写,意思是结构化查询语⾔,是⼀种在数据库管理系统中查询或对数据库⾥⾯的数据进⾏更改的语⾔
数据定义语⾔DDL(Data Definition Language)
SQL数据定义语⾔主要⽤来定义逻辑结构,包括定义基表,视图和索引。
删除表 定义表 修改表
数据查询语⾔DQL(Data Query Language)
数据操纵语⾔DML(Data Manipulation Language)
数据控制功能DCL(Data Control Language)
综合统⼀(独⽴完成数据库⽣命周期中的全部活动,包括定义关系模式、录⼊数据、建⽴数据库、査询、更新、维护、数据库重构、数据库安全性控制等⼀系列操作)
⾼度⾮过程化 (⽤户只需提出“做什么”,⽽不必指明“怎么做”。)
⾯向集合的操作⽅式 (SQL采⽤集合操作⽅式)
以同⼀种语法结构提供两种使⽤⽅式(SQL既是⾃含式语⾔,⼜是嵌⼊式语⾔。SQL语句能够嵌⼊到⾼级语⾔程序中)
语⾔简洁,易学易⽤ (SQL语⾔语法简单,接近英语⼝语,因此容易学习,也容易使⽤。)
char(n),character(n) 长度为n的定长字符串
varchar(n),charactervarying(n) 最大长度为n的变长字符串
clob 字符串大对象
blob 二进制大对象
int,integer 4字节长整数
smallint 2字节短整数
bigint 8字节大整数
numeric(p,d) 定点数,由p位数字组成,小数点后面有d位数字
decimal(p,d),dec(p,d) 同numeric
real 取决于机器精度的单精度浮点数
double precision 取决于机器精度的双精度浮点数
float(n) 可选精度的浮点数,精度至少位n位数字
boolean 逻辑布尔值
data 日期
time 时间
timestamp 时间戳类型
interval 时间间隔类型
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
create schema <模式名> authorization <用户名> [<表定义子句>|<视图定义子句>|<授权定义子句>];
create schema "Learn" authorization zhangxu create table user( id int primary key , age int ,name varchar(255));
DROP SCHEMA <模式名> <CASCADE|RESTRICT>;
删除模式, 其中 CASCADE 和RESTRICT 必须⼆选⼀,
CASCADE是(级联)
RESTRICT(限制)
create table表名(字段名 类型 字段约束,字段名 类型 字段约束,字段名 类型 字段约束)//创建表
create table user(
name varchar(20),
age int,
sex char(1)
)
drop table <表名> <CASCADE|RESTRICT>;
CASCADE呢 是如果表有外键,视图 触发器的话,也会强⾏删除, RESTRICT恰恰相反
修改
alter table <表名> [add [column] <新列名><数据类型>[完整性约束]][add <表级完整性约束>]
alter table test add email VARCHAR(255);
数据量⽐较⼤的时候, 查询耗时间⻓, 建⽴索引可以有效减少消耗时间
索引可以建⽴在⼀列或者多列上
建立:
create [unique][cluster] index <索引名> on <表名>(<列名>[<次序>]...);
CLUSTER :聚簇索引:物理顺序与索引的逻辑顺序相同。⽐如买书,C区必须在A区B区后面
UNIQUE 唯⼀索引,
例如
CREATE UNIQUE Stusno INDEX ON Student(Sno);
ALTER INDEX<旧索引名>RENAME TO<新索引名>;
例子:将SC表的SCno索引名改为SCSno。
ALTER INDEX SCno RENAME TO SCSno;
DROP INDEX<索引名>;
[例]删除Student表的Stusname索引。
DROP INDEX Stusname;
select * from Student;
等价于select Sno,Sname,Ssex,Sage,Sdept from Student;
select Sno from SC;
给列起别名
select username 名字 from user;
等价于
select username as 名字 from user;
给表起别名
select username from user u;
等价于
select username from user as u;
select distinct title from edu_course;
查询 不重复 标题 从 表中
select * from edu_course where price>2;
查询 所有 来自 表 要求 价格高于2
select * from edu_course where price between 21 and 50;
查询 所有 来自 表 要求 价格在21和50之间
select * from edu_course where teacherid in (1,2,3);
查询 所有 来自 表 要求 老师id在123集合之间
select * from edu_course where title like '%速成';
查询 所有 来自 表 要求 标题 想 任何几个字符+速成
% 任何几个字符
_ 任意1个字符
select * from edu_course where title like '_速成';
查询 所有 来自 表 要求 标题 想 1个字符+速成
% 任何几个字符
_ 任意1个字符
因为% 可以代替多个字符, 但是_ 只能替换⼀个字符
select * from edu_course where (price>2 and teacher_id=1) or (title= "mysql速成');
查询 所有 来自 表 要求 (价格>2 并且 老师id=1) 或者 (标题为mysql速成)
select * from edu_course ORDER BY lesson_num;
查询 所有 来自 表 按课程数量排序
select * from edu_course ORDER BY lesson_num DESC;
查询 所有 来自 表 按课程数量倒序排序
AVG() - 返回集合的平均值。
COUNT() - 返回集合中的项目数。
MAX() - 返回集合中的最大值。
MIN() - 返回集合中的最小值
SUM() - 返回集合中所有或不同值的总和。
select count(title) from edu_course;
查询 title列中的属性个数 来自 表
包括重复,不含空NULL
select count(distinct title) from edu_course;
查询 title列中不重复的属性个数 来自 表
不包括重复,不含空NULL,加上DISTINCT是去除列⾥⾯重复的 来计算
select avg(price) from edu_course;
价格平均值
select max(price) from edu_course;
价格最大值
select min(price) from edu_course;
价格最小值
GROUP BY
分组 ,如果要进行筛选,请使用Having
select title FROM edu_course GROUP BY title
按照title进行分组,相同title一组
select title FROM edu_course GROUP BY title having title='SSM速成';
按照title进行分组,相同title一组,查询title为SSM速成的一组
select t.* ,c.* from edu_teacher t ,edu_course c where t.id=c.teacher_id;
查询 t表全部和c表全部 从 edu_teacher表 别名t edu_course表 别名c 连接 t的id和c的tid同
Select c1.version,c2.view_count from edu_course c1 ,edu_course c2 where c1.version=c2.view_count;
select * from edu_course ec left outer join edu_course_description ecd on ec.id=ecd.id;
select * from edu_course ec right outer join edu_course_description ecd on ec.id=ecd.id;
select * from edu_course ec inner join edu_course_description ecd on ec.id=ecd.id;
select c.id ID ,c.title 课程名,cp.title 章节,cd.description 课程措述 from edu_course c ,edu_chapter cp,edu_course_description cd where c.id=cp.course_id and c.id=cd.id
查询 c表中id 别名ID,c表中title 别名课程名,cp表中title别名章节,cd表中的description别名课程措述 从edu_course表,别名c ,edu_chapter表,别名cp,edu_course_description表别名cd,连接 c.id=cp.course_id 和 c.id=cd.id
select c.title 课程名,c.price 价格 from edu_course c where c.title in (select c2.title from edu_course c2 where c2.title="mysql速成");
select c2.title from edu_course c2 where c2.title="mysql速成"
在c2表中查出title="mysql速成"的表
select c.title 课程名,c.price 价格 from edu_course c
从c表中查出课程名和价格
where c.title in()
要求从c表中查出课程名在c2表中查出title="mysql速成"的表里面
select c.title课程名,c.price价格 from edu_course c where c.price >ALL(select c2.price from edu_course c2 where c.price between 1 and 20) ;
1.在edu_course表中查出价格在1到20之间的价格,组成一张表
2.edu_course中查询价格高于()表中所有价格的行,组成一张表
3.2中表只保留title和price
select c.title 课程名,c.price价格 from edu_course c where c.price >ANY (select c2.price from edu_course c2 where c2.price between 22 and 24);
1.在edu_course表中查出价格在22到24之间的价格,组成一张表
2.edu_course中查询价格高于()表中最低价格的行,组成一张表
3.2中表只保留title和price
not exists 如果后⾯的⼦查询没有值,返回1 否则为0
exists 相反 如果后⾯的⼦查询有值,返回1 否则为0
例如:查询这样的学生,没有一门课程是他不选修的(他选修了所有课)。其SQL语句如下:
select Sname from Student where NOT EXISTS
(select * from course where NOT EXISTS
(select * from SC where Sno=Student.Sno and Cno=Course.Cno));
查询他选择的所有的课程门数SC select * from SC 。。。
查询他没有选择的所有的课程门数SC NOT EXISTS (select * from SC 。。。
查询所有课程 (select * from course where 。。。o));
查询没选的所有课程 NOT EXISTS (select * from course 。。。no));
最里面的子查询是这个人没选一门课程
外面的子查询是没有这样的课程
select * from student where sdept = "cs" union select * from student where sage <= 19;
select * from student where sdept = "cs" intersect select * from student where sage <= 19;
select * from student where sdept = "cs" except select * from student where sage <= 19;
insert into 表名 [( 字段列表 )] values( 值列表 ...);
//标准添加(指定所有字段,给定所有的值)
insert into stu(id,name,age,sex,classid) values
( 1 , 'zhangsan' , 20 , 'm' , 'lamp138' );
//指定 部分 字段添加值
insert into stu(name,classid) value( 'lisi' , 'lamp138' );
//不指定 字段添加值
insert into stu value( null , 'wangwu' , 21 , 'w' , 'lamp138' );
//批量 添加值
insert into stu values
( null , 'zhaoliu' , 25 , 'w' , 'lamp94' ),
( null , 'uu01' , 26 , 'm' , 'lamp94' ),
( null , 'uu02' , 28 , 'w' , 'lamp92' ),
( null , 'qq02' , 24 , 'm' , 'lamp92' ),
( null , 'uu03' , 32 , 'm' , 'lamp138' ),
( null , 'qq03' , 23 , 'w' , 'lamp94' );
update 表名 set 字段1= 值1, 字段2= 值2, 字段n= 值n... where 条件
-- //将 id 为 11 的 age 改为 35 , sex 改为 m 值
update stu set age=35 ,sex='m' where id= 11 ;
格式: delete from 表名 [where 条件 ]
//删除stu表中id值为100的数据
delete from stu where id=100;
视图(VIEW)也被称作虚表,即虚拟的表,是⼀组数据的逻辑表示,
其本质是对应于⼀条SELECT结果集被赋予⼀个名字,即视图名字。
视图本身并不包含任何数据,它只包含映射到基表的⼀个查询语句,当基表数据发⽣变化,视图中的数据也会发生变化
⽬的: ⽅便,简化数据操作
当我们业务需求要查出多张表的数据,这时我们可能会关联多张表查询处理.
如果这个查询sql复杂的话也影响了查询效率.
这个时候我们就可以创建视图,查询时候只需要 select * from view 就ok啦~
create view <视图名> [(<列名>...)] as <子查询> [with check option];\
例如:
create view IS_student as select sno,sname,sage from student where sdept ='IS' with check option;
加了WITH CHECK OPTION可以防⽌⽤户对 不属于试图范围的操作 进⾏拒绝
删除视图:
drop view <视图名>[cascade];
例如:
select sno,sage from is_student where sage<20;
例如:
update is_student set sname ='liu' where sno = '111';
转换后的更新语句为:
update student set sname = 'liu' where sno = '111' and sdept = 'IS';
静态⼝令鉴别
动态⼝令鉴别
⽣物特征鉴别
智能卡鉴别
字⾯意思就是我们⽤户可以⾃定义和分配其他⽤户的操作
主要通过grant
和revoke
来进⾏控制
由两个元素构成: 数据库对象 和 操作权限
我们定义⽤户的存取权限为授权
grant <权限> on table <表名> to <⽤户>;
revoke <权限> on table <表名> from <⽤户>;
Grant <权限> on 表名[(列名)] to ⽤户 With grant option
REVOKE <权限> ON <数据对象> cascade
cascade 加了,在回收的时候,会回收他赋予其它人的权限
revoke翻译:vt.撤销,取消;废除
//授予用户user1拥有对表student的查询权限
Grant select on student to user1 with grant option
revoke select on student from user1
create role <角色名>
create role CEO
grant <权限> on <对象类型> 对象名 to <角色1>,<角色2>
grant select on Student to CEO
grant <角色>to 角色或者用户名字 [with admin option]
grant CEO to lihua
revoke<权限> on<对象名>from 角色名字
revoke select on Student from CEO
create view CS_Student as select* from student where sdept='IS';
grant select on CS_Student to 王平;
grant all privilegeson CS_Student to 王平;
audit update on sc;
noaudit update on sc;
正确性
相容性
维护完整性
主码唯⼀,且⾮空
⽐如我的地址,年龄在两个表⾥⾯都应⼀致
create table course (id int not null ,time varchar(255),primary key(id));
create table course (id int not null primary key,time varchar(255));
create table course (id int,time varchar(255),title varchar(255),teacher_id int,
primary key(id),foreign key (id) references course_description(course_id);
course表有id
course_description 表有id和course_id
查询:
select * from course c,course_description cd where c.id=cd.course_id
create table student(
no char(9) primary key,
age int not null
);
create table student(
no char(9) primary key,
age int unique
);
create table student(
no char(9) primary key,
sex char(2) check (sex in ('男','⼥')),
age int not null
);
create assertion <断⾔名> <check⼦句>
drop assertion 断⾔名字;
触发器也叫做 事件->条件->动作 规则.
当对⼀个表增 删 改时候, 对触发器⾥⾯的条件进⾏检查,
如果成⽴,就执⾏触发器⾥⾯的动作.否则不执⾏⾥⾯的动作.
添加触发器
create trigger <触发器名> /*每当触发事件发生时,该触发器被激活*/
{before |after} <触发事件> on <表名> /*指明触发器激活时间是在执行触发事件前或后*/
referencing new|old row as<变量> /*referencing指出引用的变量*/
for each{row|statement} /*定义触发器的类型,指明动作体执行的频率*/
[where <触发条件>]<触发动作体> /*仅当触发条件为真时才执行触发动作体*/
drop trigger <触发器名> on <表名>
设计关系数据库时,遵从不同的规范要求,这些不同的规范要求被称为不同的范式,
各种范式呈递次规范,越⾼的范式数据库冗余越⼩。
⽬前关系数据库有六种范式:第⼀范式(1NF)、第⼆范式(2NF)、第三范式(3NF)、
巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,⼜称完美范式)。
⼀般来说,数据库只需满⾜第三范式(3NF)就⾏了。
X→Y,但Y⊈X,则称X→Y是非平凡的函数依赖
X→Y,但Y⊆X,则称X→Y是平凡的函数依赖
概念:可以推出所有属性
如何选出候选码?
⽐如
R, U(A,B,C,D,E,G), F={AB-->C, CD-->E, E-->A, A-->G) ,求候选码:
F中只出现在左边的一定是候选码:B⼀定是候选码 ,D⼀定是候选码
F中只出现在右边的一定不是候选码:G⼀定不是候选码
F中左右都出现的不一定:A不⼀定C不⼀定 E不⼀定
再求确定的候选码的闭包:BD->啥也推不出来,所以要把每⼀个可能的求闭包
(BDA)+= 可推出C E A G所以可以推出ABCDEG
(BDC)+= 可推出 E A G所以可以推出ABCDEG
(BDE)+= A G C可以推出ABCDEG
那么他的候选码最终是{ (BDA),(BDC),(BDE) };
比如(BDA),(BDC),(BDE)BDCA BDEA ABCDE
候选码是最小的超码.
主码:从候选码里面任意挑出一个作为主码
主属性:包含在所有候选码的属性比如ABCDE
非主属性:不包含在候选码中的属性,上题为G
全码:所有的属性都是主码
1NF : 所有字段值都是不可分解的原子值
2NF : 不包含非主属性对码的部分函数依赖,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中
3NF : 不包含非主属性对码的传递函数依赖,确保数据表中的每一列数据都和主键直接相关,而不能间接相关
BCNF : 消除每一属性对候选键的传递依赖,BCNF是修正的第三范式
比如某些数据库系统中需要用到“地址”这个属性,
本来直接将“地址"属性设计成一个数据库表但是如果系统经常会访问“地址"属性中的“城市"部分,
那么就非要将“地址"这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,
这样在对地址中某一部分操作的时候将非常方便
一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中
该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。
所以在这里违反了第二范式的设计原则
存在关系∶
书号-书名
(书名、作者)→书号
上述关系存在传递依赖,不能是BCNF
Armstrong公理系统:一套推理规则,模式分解算法的理论基础
用途:1.求给定关系模式的码 2.从一组函数依赖求得蕴涵的函数依赖
自反律,增广律,传递律,可得到合并规则,伪传递规则,分解规则
自反律,增广律,传递律称为Armstrong公理系统,该系统是有效的,完备的
合并规则:由X→Y,X→Z,有X→YZ.
伪传递规则:由X→Y,WY→Z,有XW→Z.
合并规则:由X→Y,Z⊆Y,有X→Y.
什么是依赖?
如何求最小依赖集?
F={B->D,DG->C,BD->E,AG->B,ADG->B,ADG->C}
最小函数依赖集求法:
(1):右边拆成单属性的,例如:ADG->BC拆成ADG->B,ADG->C;
(2):F中去掉X->Y,求X->Y左边X的闭包X+,若Y属于X+,则删去多余,否则保留。例如B->D,B+={B},则保留。
(3):X->Y左边的拆成单属性,然后求个单属性的闭包,若Y属于单属性闭包,则删去拆掉的闭包。例如:BD->E拆成B->E,D->E,B+={BDE},E属于B+,所以删去D;D+={D}不变。故BD->E用B->E代替。
(1)(2)求得:
Fm={B->D,DG->C,BD->E,AG->B}
(3)求得:
Fm={B->D,DG->C,B->E,AG->B}
最终答案:Fm={B->D,DG->C,B->E,AG->B}
准则: ⽆损连接 和 保持函数依赖
已知R(ABCDEGH) ,F={A->D,E->D,D->B,BC->D,DC->A} ,求保持函数依赖的3NF
的分解
1) 求出最⼩函数依赖集
2)把不在F⾥⾯的属性都找出来,单独分⼀类
3) 把每⼀个依赖左边相同的分成⼀类,没有⼀样的,那么就把A->D改为{AD},如果⼀样{A->B,A->C} 那么久改为{ABC}
4) 如果候选码没出现在分离⾥⾯, 把任意⼀个候选码作为⼀类
最先函数依赖集Fmin={A->D,E->D,D->B,BC->D,DC->A}
GH没在F⾥⾯, 单独⼀类{GH}
候选码: CE ACE
{AD}{ED}{DB}{BCD}{DCA }{CE}{GH}
嵌入式SQL
嵌入式SQL的处理过程:
SQL与主语言的通信
查询优化的四个阶段:
事务的四大特性:ACID
A:原子性autom 要么全做,要么全不做
c:一致性consistent 一致性与原子性密切相关,要么全做要么全不做,否则就会造成数据不一致。比如说︰银行汇钱,两边都要有操作才行
I∶隔离性isolate 一个事务的执行不能被其他事务所干扰
D︰持久性duration 数据库的改变是永久的。比如要落入磁盘
事物内部故障
系统故障DBMS
介质故障
计算机病毒
数据转储
对失败的事务重新执行
日志文件
记录事务对数据的更新操作的文件
丢失修改
读脏数据
⽐如,你要读取数据库中的字段A、字段B,你读取时恰巧有其他⽤户正在更新这2个字段,而且是先更新A、再更新B,
⽽且如果那个⽤户更新⼀半你就读取了,也就是说更新了A,正打算要更新B但尚未更新时,你就读取了,此时你得到的就是脏数据
不可重复读
我在⼀个事务中,连续两次读到的数据不⼀样。
⽐如我刚开始读到银⾏余额为10元。此时单位突然给发⼯资100到这张卡,那么我第⼆次读就变110元
排它锁:也叫写锁
共享锁:也叫读锁
⼀级封锁协议
⼆级封锁协议
三级封锁协议
假设多种情况都可以,然后获得结果,
如果并发执⾏的结果跟上⾯的结果⾥⾯任意⼀个⼀样就可以
事务T1: 读取B,A=B+1,写回A
事务T2: 读取A,B=A+1,写回B
那么结果假设先T1, 在T2 , 那么A=4,B =3;
假设先T2 ,那么A=3, B =4;