diff --git "a/39 \347\216\213\351\233\252\345\275\261/20231023 \347\254\224\350\256\260.md" "b/39 \347\216\213\351\233\252\345\275\261/20231023 \347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..ba4610e20db15e2ee78b53a6006b9d6ad2bd83a4 --- /dev/null +++ "b/39 \347\216\213\351\233\252\345\275\261/20231023 \347\254\224\350\256\260.md" @@ -0,0 +1,28 @@ +今天讲解了sql50题 还复习了一点数据库设计 + +### 表之间的关系: + +(1)一对一的关系:一个公民只有一个身份证号 + +(将其中任一表中的主键放在另一张表中当外键) + +(2)一对多的关系(多对一的关系):一个班级有多个学生 + +(将一所在表的主键放到多的表中当外键) + +(3)多对多的关系:一个学生可以选修多门课程,一个课程可以被多个学生选修 + +(需要一张中间表,把两张表的主键放在第三张表中当外键) + +### RBAC + +基于角色的权限访问控制 + +通过将用户分配到不同的角色,从而赋予用户相应的权限。 + +RBAC模型的核心是角色,而不是用户,角色扮演者可以是用户、组织机构、应用程序等,而权限则是分配给角色,而非用户。 + +(1)SPU:一个商品有很多规格 + +(2)SKU:由不同属性构成了一个规格,不同的商品属性组合而成的最小单位 + diff --git "a/39 \347\216\213\351\233\252\345\275\261/20231025 \347\254\224\350\256\260\346\200\273\347\273\223.md" "b/39 \347\216\213\351\233\252\345\275\261/20231025 \347\254\224\350\256\260\346\200\273\347\273\223.md" new file mode 100644 index 0000000000000000000000000000000000000000..f49c9730f41684c577a354b23c8b38a8be908a6e --- /dev/null +++ "b/39 \347\216\213\351\233\252\345\275\261/20231025 \347\254\224\350\256\260\346\200\273\347\273\223.md" @@ -0,0 +1,1072 @@ +# 笔记总结 + +# 一、数据库设计 + +根据用户需求和开发的系统的需求,设计出符合对应的DBMS的需求的数据库设计,使其能有效的存储和管理数据 + +### 1.表之间的关系: + +(1)一对一的关系:一个公民只有一个身份证号 + +(将其中任一表中的主键放在另一张表中当外键) + +(2)一对多的关系(多对一的关系):一个班级有多个学生 + +(将一所在表的主键放到多的表中当外键) + +(3)多对多的关系:一个学生可以选修多门课程,一个课程可以被多个学生选修 + +(需要一张中间表,把两张表的主键放在第三张表中当外键) + +### 2.E-R图 + +(1)概念:实体关系图,简记E-R图,是指以实体、关系、属性三个基本概念数据的基本结构,从而描述静态数据的概念模式 + +(2)要素 + +实体、关系、属性 + +(3)表示 + +实体型:用矩形表示,矩形框内写明实体名 + +属性: + +①用椭圆形或圆角矩形表示,与相应的实体连接起来 + +②主属性名称下加下划线 + +联系(关系): + +①用菱形表示,菱形框内写明联系的名称 + +②用线与实体相连,可标上联系的类型 + +③联系也可以有自己的属性 + +(4)关系 + +在E-R图中要明确表明一对多关系,一对一关系和多对多关系 + +①一对一关系在两个实体连线方向写1 + +②一对多关系在一的一方写1,多的一方写N + +③多对多关系则是在两个实体连线方向各写N,M + +### 3.数据库的三大范式 + +(1)第一范式:每个属性,也就是每个字段要求不可再分割,也就要求有原子性 + +(2)第二范式:在满足第一凡事都饿基础上,要求非主键字段要完全依赖主键(有联合主键时非主键要同时完全依赖这两个主键,不能部分依赖) + +(3)第三范式:在满足第二范式的基础上,要求非主键字段要直接依赖于主键 + +### 4.RBAC + +基于角色的权限访问控制 + +通过将用户分配到不同的角色,从而赋予用户相应的权限。 + +RBAC模型的核心是角色,而不是用户,角色扮演者可以是用户、组织机构、应用程序等,而权限则是分配给角色,而非用户。 + +(1)SPU:一个商品有很多规格 + +(2)SKU:由不同属性构成了一个规格,不同的商品属性组合而成的最小单位 + + + +# 二、视图 + +### 1.视图概念 + +(1)视图是一种虚拟表,本身是不具有数据的,占用很少内存空间,是SQL中的一个重要概念(可以将视 + +图理解为储存起来的select语句) + +(2)视图建立在已有表的基础上,视图赖以建立的这些表叫做基表 + +(3)视图的创建和删除只影响视图本身,不影响对应的基表,但是当对视图中的数据进行增加、删除和修 改操作时,数据表中的数据会相应地发生变化,反之亦然 + +### 2.创建视图 + +```sql +create view 视图名称 as 查询语句; +``` + +### 3.修改视图 + +```sql +create or replace view 视图名称 as 查询语句; +``` + +```sql +alter view 视图名称 as 查询名称; +``` + +### 4.删除视图 + +```sql +drop view if exists 视图名称; +``` + +删除任何视图都不会影响基表 + +### 5.更新视图的数据 + +可以使用insert、update和delete语句对视图中的数据进行插入、更新和删除操作 + +举例:update + +```sql +update emp_tel set tel="1234567" where ename="张三"; +``` + +举例:delete + +```sql +delete from 表名 where 条件; +``` + +### 6.不可更新的视图 + +(1)在定义视图的时候指定了"ALGORITHM=TEMPTABLE",视图将不支持insert和delete操作 + +(2)视图中不包含基表中所有被定义为非空又未指定默认值的列,视图将不支持insert操作 + +(3)在定义视图的select语句中使用了join联合查询,视图将不支持insert和delete操作 + +### 7.修改视图名称(与修改表名称对比) + +(1)修改表名称 + +```sql +rename table 旧表名称 to 新表名称; +``` + +(2)修改视图名称 + +```sql +rename table 旧视图名称 to 新视图名称; +``` + +### 8.查看视图 + +(1)语法1:查看数据的表对象,视图对象 + +```SQL +show table; +``` + +(2)语法2:查看视图的结构 + +```SQL +desc 视图名称; +``` + +(3)语法3:查看视图的详细定义信息 + +```SQL +show create view 视图名称; +``` + +### 9.指定字段创建视图 + +```sql +create view 视图名称(指定字段名1,指定字段名2,指定字段名3...) as 查询语句; +``` + +注:1.视图中的自定义字段名(括号中的)不用加引号,但查询语句中的别名的引号可加可不加 + +​ 2.括号中的指定字段名要与查询语句中的一一对应 + +### 10.concat函数 + +concat 字符串合并函数,可以合并N个字符串 + +例:名 三,姓 张,行政部 ==》[行政部]:张三 + +```sql +concate ('[','部门',']:','张','三') +``` + +# 三、单行函数 + +### 1.生成随机数: + +```sql +select rand(); 返回0~1的随机数 +``` + +### 2.返回字节数: + +```sql +select length("a") 字母返回1 +``` + +### 3.拼接字符串: + +```sql +select concat(123,456); 返回123456 +select concat_ws('-',123,456); 返回123-456 +``` + +### 4.修改字母大小: + +```sql +改大写:select upper('abc'); 返回ABC + +改小写:select lower('ABC'); 返回abc +``` + +### 5.截取: + +(1)从左取: + +```sql +select left(123456,3); 返回123 +``` + +(2)从右取: + +```sql +select right(123456,3); 返回456 +``` + +(3)截取: + +①substr() ②substring() ③mid() + +```sql +select substr/substring/mid(123456781234567812,7,8); 返回781234 +``` + +mysql中字符的索引位置是从1开始的,不是0 + +(4)截取字符还可以用left、right + +select left( , ) + +### 6.去空格 + +去两边:select trim() +只去左边:select ltrim() +只去右边:select rtrim() + +### 7.分割字符串: + +```sql +subtring_index(原字符串,'分界字符',数字); +``` + +数字表示截第几个字符,数字大于零截左边的,数字小于零截右边的 + +### 8.填充补位 + +```sql +select lpad(1,8,0) 返回00000001 +lpad(原字符串,填充长度,填充内容) +``` + +### 9.取整 + +select floor( rand());向下取整 + +select ceil (rand());向上取整 + +### 10.保留几位小数点 + +truncate(x,y)截取x小数点后y位 + +truncate+表名 清空表 + +### 11.字母转大小写 + +转大写:upper + +转小写:lower + +### 12.ABS(x) 返回数值的绝对值 + +### 13.round(x) 返回对x四舍五入之后的值 + +round(x,y) 返回对x四舍五入之后的值,并保留小数点y位 + +### 14.mod(x,y) 返回x除以y后的余数 + +# 四、存储过程 + +### 1.概念: + +用于完成一次完整的业务处理,没有返回值,可通过传出参数给多个值 + +### 2.基本语法: + +(1)创建 + +存储过程分为有参、无参存储过程 + +```sql +delimiter // -- 修改定界符为//(符号可以自定义,只要不是 \ ) +CREATE PROCEDURE 存储过程名称 ([ in/out/inout 参数名 参数数据类型 ]) +BEGIN +-- 真正要执行的sql语句集合(集合的意思是sql语句可以是N条,可以是查询、插入、修改、删除语句,基本DDL)每句sql语句都用 ; 结束 +END // +delimiter ; -- 将定界符还原为 ; +``` + +(2)调用 + +```sql +call 名称 ([ 参数 ]); -- 如果()里没有参数,可以把()省略 +``` + + + +(3)查看 + +```sql + SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'xxx'; + -- 查询指定数据库的存储过程及状态信息 +SHOW CREATE PROCEDURE 存储过程名称 ; +-- 查询某个存储过程的定义 +``` + +-- 删除 + +```sql + DROP PROCEDURE [ IF EXISTS ] 存储过程名称; + -- 存储过程不支持直接修改过程的语法,需要先删除原有的过程,再重新建一个同名的,删除时不需要加() +``` + + 注意: +在命令行中,执行创建存储过程的SQL时,需要通过关键字 delimiter 指定SQL语句的结束符。 + +(4)定义一个参数的语法包括参数模式、参数名称、参数数据类型 + +- IN输入参数:表示调用者向过程传入值(传入值可以是字面量或变量) +- OUT输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量) +- INOUT输入输出参数:既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量) + +存储过程可以有0个或多个参数,用于存储过程的定义。 + +① in 入参 + +② out 出参 + +```sql +delimiter // +create procedure 存储过程名称(in myid int,out myname varchar(20)) -- 传入编号传出名称 +begin +select first_name into myname from employees where employee_id=myid; +end // +delimiter ; +call 存储过程名称 (100,@newname); +select @newname; +``` + +③ inout 入参出参 + +```sql +delimiter // +create procedure 存储过程名称(inout myname varchar(20)) -- 传入含有空格的名字传出去除空格的名字 +begin +set myname=trim(myname); +end // +delimiter ; +set @name1=' 李小龙 ' +call 存储过程名称 (@name1); +select @name1; +``` + +注:在参数模式中只要含有out的,调用传参时,一定要用会话变量 + +# 五、变量 + +1.mysql中的变量分为两大类,一是系统的变量,二是用户的变量(可自定义的) + +用户变量可分为会话变量(成员变量)和局部变量 + +局部变量的作用域为begin和end之间 + +(1)系统变量:用@@global.变量名,指系统已经定义好的变量 + +(2)用户变量:可自定义的变量 + +① 会话变量:用@ 变量名表示 + +​ 作用域:同一会话中可任意调用,不用定义直接使用 + +② 局部变量:直接用,不带@标识符表示 + +​ 作用域:begin和end之间 + +注:使用局部变量前一定先定义,定义变量之前不能有其他语句 + +declare 变量名 变量数据类型 [defult 默认值] + +2.赋值方式 + +(1)方式一:直接赋值 + +​ 定义一个局部变量 + +```sql +declare myname varchar(10); +``` + +给变量赋值(通用、会话、局部也都是一样的)有两种方式、 + +```sql +set myname='小明'; +``` + +(2)方式二:将查询结果赋值给变量 + +```sql +declare myfname varchar(10); +declare mylname varchar(10); +select first_name,last_name into myfname,mylanme from employees where employee_id=100; +select myfname,mylname; +``` + +总结: ① set 变量名=值 + +​ ②select 值 into 变量; + +# 六、分支结构 + +### 1.if + +存储过程中是支持 if 这种条件判断的分支结构,但是不能用在 select 查询字段中 + +if 可以判断某个值也可以判断区间 + +语法: + +```sql +if 条件 then sql语句 +[elseif 条件2 then 语句2;] -- 语句后面要加; +…… +[ELSE 操作N] +END IF; +-- 关键字then后只能加语句 +``` + +### 2.case + +(1) + +```sql +case 表达式 +when 值1 then 结果1或语句1(如果是语句,需要加分号) +when 值2 then 结果2或语句2 +... +ELSE 结果n或语句n +end [case]; +-- 如果是放在begin end中需要加上case,如果放在select后面不需要 +``` + +(2) + +```sql +case +where 条件1 then 结果1或语句1(如果是语句,需要加分号) +where 条件2 then 结果2或语句2 +... +ELSE 结果n或语句n +end [case]; +-- 如果是放在begin end中需要加上case,如果放在select后面不需要 +``` + +# 七、循环 + +存储过程中的循环结构,任何循环一定会有一个改变循环条件的语句 + +1.loop 死循环 + +不需要条件的死循环(里面要有终止循环的条件) + +```sql +[loop_label:] LOOP +循环执行的语句 +END LOOP [loop_label] +-- loop 循环中关键字leave即可退出循环,也可以退出begin,必须要跟上标识符 +``` + +2.while 有条件的循环 + +一开始就明确了开始条件和结束条件,满足条件才会进入循环 + +```sql +WHILE 条件 DO -- 条件是为了进入循环 +SQL语句 +END WHILE; +``` + +3.repeat + +先执行一次,再判断是否符合循环的条件(条件是为了退出循环) + +```sql +REPEAT +循环体的语句 +UNTIL 结束循环的条件表达式 +END REPEAT; +``` + +# 八、存储函数 + +存储函数是有返回值的存储过程,存储函数的参数只能是IN类型的。 + +### 1.创建语法 + +```sql +CREATE FUNCTION 存储函数名称 (参数名 参数类型) (函数没有模式直接写类型) +RETURNS 返回值类型 -- 存储函数只能返回一个值,有返回值就要声明他的数据类型 +[characteristic ...] -- deterministic contain sql 或 deterministic no sql +BEGIN +-- SQL语句 一定要有return语句,return语句写在最后 +RETURN ...; +END ; +``` + +### 2.查询创建语句 + +```sql +show create function 函数名; +``` + +### 3.修改 + +跟存储过程一样先删再建 + +```sql +drop function 函数名; +``` + +### 4.调用 + +```sql +select 函数名(); +``` + +# 九、游标 + +### 1.定义游标 + +定义变量要放在定义游标之前 + +```sql +DECLARE 游标名称 CURSOR FOR 查询语句 ; +``` + +### 2.打开游标 + +```sql +OPEN 游标名称 ; +``` + +### 3.获取游标记录 + +(游标每次只取一样) + +```sql +FETCH 游标名称 INTO 变量 [, 变量 ] ; +``` + +### 4.关闭游标 + +```sql +CLOSE 游标名称 ; +``` + +示例: + +```sql +delimiter // +create procedure 名称() +begin +-- 定义变量要放在定义游标之前 +declare uname varchar(20); +declare usex int; +declare i int defult 1; +declare countnum int; +--定义游标 +declare 游标名称 cursor for select name,sex from student; +select count(*) into countnum from student; + +create table boy( +id int pirmary key, +uname varchar(50), +usex char(1) +); +create table girl( +id int pirmary key, +uname varchar(50), +usex char(1) +); + +-- 打开游标 +open 游标名称; + +while i<=countnum do +-- 使用游标:每次只取一样 +-- 从游标里取值并赋值给变量,有几个值就要几个变量,数量、位置、类型都要对得上 +fetch 游标名称 into uname,usex; +if usex=1 then insert into boy values (null,uname,'男'); +elseif usex=0 then insert into gril values (null,uname,'女'); +end if; +set i=i+1; +end while; +-- 关闭游标 +close 游标名称; +end // +delimiter; +``` + +## 处理错误 + +```sql +declare continue/exit handle for 1329 set flag=0; +open 游标名称; +whil flag is null do +....... +``` + +# 十、触发器 + +### 1.语法 + +```sql +delimiter // +create trigger 触发器名称 +before/ after(触发时机) insert/ update/ delete(触发类型) +on 表名 for each row -- 行级触发器 +begin +触发的语句 +end // +delimiter; +``` + +### 2.查看 + +```sql +show triggers; +``` + +### 3.删除 + +```sql +drop trigger 触发器名称; +``` + +### 4.故意报错 + +```sql +signal sqlstate 'MD001(随便五个字符)'set message_text='错误'; +``` + +# 十一、公共表达式(CTE) + +```sql +with 表达式名称 as (子查询) + +select/delete/update 语句; +``` + +支持多个表达式 + +# 十二、窗口函数 + +### 1.语法 + +```sql +窗口函数名称(参数) OVER([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC]) +-- partition by 分组 等价于 group by +或者是: +函数 OVER 窗口名 … WINDOW 窗口名 AS ([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC]) +-- OVER 关键字指定函数窗口的范围。 +``` + +### 2.序号函数 + +row_number()、rank()、dense_rank() + +① row_number():不管排名是否有相同,都按照顺序1,2,3,4...n + +② rank():排名相同的名次一样,相同的有几个,后面就跳过几次 + +③ dense_rank():排名相同的名词一样,且后面名次不跳跃 + +### 3.开窗聚合函数 + +sum()|avg()|min()|max()|count()| over (partition by ... order by...) + +### 4.窗口大小 + +① 当前行:current row + +② 前一行:preceding + +③ 后一行:following + +④ 起始行:unbounded preceding + +⑤ 最终行: unbounded following + +-- rows 启用窗口大小 +-- between ... and ... 范围区间 + +### 5.日期函数 + +(1)获取当前日期 + +```sql +select curdate(); +``` + +(2)获取当前时间 + +```sql +select curtime(); +``` + +(3)获取当前日期时间 + +```sql +select now(); +``` + +(4)从日期字符串获取日期 + +```sql +select date('2000-02-02'); +select date('2000-02-02 12:12:12'); -- 只获取日期 +``` + +(5)天数差 + +```sql +select datediff('2001-02-02','2000-02-02'); -- 前减后 +``` + +(6)指定差 + +```sql +select timestampdiff(day,'2001-02-02','2000-02-02'); -- 后减前 +``` + +(7) 日期减法 + +```sql +select subdate('2001-02-02',interval 2 day); +``` + +(8)日期加法 + +```sql +select adddate('2001-02-02',interval 2 day); +``` + +(9)获取某日期中的值 + +```sql +select year('2001-02-02'); +select day('2001-02-02'); +select dayofyear('2001-02-02'); +select dayofweek('2001-02-02'); +``` + +(10)获取该月最后一天 + +```sql +select last_day('2001-02-02'); +``` + +(11)日期格式 + +```sql +select date_format('2001-02-02','%Y'); +``` + +### 6.前后函数 + +返回当前行的前某一行的值,或者后某一行的值 + +lag(列名,前第n行) + +lead(列名,后第n行) + +### 7.头尾函数 + +返回第一个或最后一个列的值 + +first_value(列名) + +last_value(列名) + +# 十三、索引 + +是帮助mysql高效获取数据的数据结构 + +### 1.创建索引 + +```sql +create index 索引名 on 表格(列名); +``` + +```sql +alter table 表名 add index 索引名(列名); +``` + +```sql +create table 表名( +..... +index 索引名(列名) +); +-- 以这种方式定义的索引,可以不指定索引名称 +``` + +### 2.删除索引 + +```sql +drop index 索引名 on 表名; +``` + +```sql +alter table 表名 drop index 索引名; +``` + + + +### 3.查看表的索引 + +```sql +show index from 表名; +``` + + + +### 4.唯一索引 + +索引烈儿的值必须唯一,但允许有空值,如果是组合索引则列值的组合必须唯一。 + +创建语法: + +```sql +create unique index 索引名 on 表名(列名); +``` + +```sql +alter table 表名 add unique 索引名(列名); +``` + +```sql +create table 表名( +....... + unique[index] 索引名(列名) +); +``` + +(1)唯一索引必须有索引名,有唯一约束就会自动有唯一索引 + +(2)约束是没有名称和index关键字的 + +(3)删除唯一索引与删除普通索引相同 + +### 5.主键索引 + +(1)有主键约束就会有主键索引 + +(2)create index不能用来创建主键索引 + +(3)创建语法: + +```sql +create table 表名( +列表名 数值类型 primary key, + ...... +); +``` + +```sql +create table 表名( +........ + primary key (列名) +); +``` + +```sql +alter table 表名 add primary key (列名); +``` + +(4)删除主键索引 + +删除主键不用drop index + +```sql +alter table 表名 drop primary key; +``` + + + +### 6.联合索引 (遵循最左前缀法则) + +(1)普通联合索引 + +```sql +create index 索引名 on 表名 (列名1,列名2,列名3....); +``` + +(2)联合唯一索引 + +```sql +create unique index 索引名 on 表名 (列名1,列名2,列名3....); +``` + + + +### 7.explain 联合计划 + +用来查看某个查询语句的执行详细情况 + +语法: + +```sql +explain select.......from......; +``` + +# 十四、事务 + +### 1.事务的几个特性 + +(1)原子性 + +一组sql语句要么全部成功,要么全部失败,不存在部分成功,部分失败的情况 + +事务是一个原子操作,是最小的执行单元,由一个或多个sql语句组成,不可分割 + +(2)隔离性 + +一个事务的执行不能被其他事务干扰,一个事务内部的操作及使用的数据对并发的其他事务是隔离的 + +(3)一致性 + +一个事务必须使数据库从一个一致性状态变换到另一个一致性状态 + +(4)持久性 + +一个事务一旦提交,他对数据库中的数据的改变是永久性的 + +### 2.事务的隔离级别 + +(1)读未提交:read uncommited + +(2)读已提交:read commited + +一个事务操作过程中可以读取到其他事务已经提交的数据。 + +事务中的每次读取操作,读取到的都是数据库中其他事务已提交的最新的数据(相当于当前读) + +(3)可重复读:repeatable read + +一个事务操作中对于一个读取操作不管多少次,读取到的结果都是一样的。 + +(ps:不可重复读 + +在同一事务中,多次读取同一数据返回的结果有所不同,换句话说,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读” 在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据) + +(4)串行化:serializable + +### 3.是否开启隐式事务是由便来你autocommit控制的 + +### 4.事务分为隐式事务和显式事务 + +(1)mysql中事务默认是隐式事务,执行insert,update,delete操作的时候,数据库自动开启事务提交,回滚。 + +(2)显示事务需要手动开启、提交或回滚 + +### 5.开启事务 + +```sql +set commit=0; +或 +start transaction; -- 不管是隐式还是显示状态,都可以临时手动开启一次事务 +``` + + + +### 6.查看自动提交的状态 + +```sql +show variables like 'autocommit'; +``` + +### 7.关闭自动提交 + +```sql +set autocommit=off; +或 +set autocommit=0; +``` + +### 8.打开自动提交 + +```sql +set autocommit=on; +或 +set autocommit=1; +``` + +### 9.回滚操作 + +会将数据还原回事务初始状态 + +```sql +rollback; +-- 回滚有附加确认的效果,一旦确认事务就结束了 +``` + +### 10.提交事务 + +将数据持久化,也就是确认数据最终状态 + +```sql +commit; +``` + +### 11.savepoint关键字 + +将大批操作分为几个部分,然后指定回滚某个部分 + +```sql +..... +savepoint part1; +..... +savepoint part2; +..... +rollback part1; +-- 有保存点的事务是分段执行的,所以回滚到某个保存点不会结束整个事务 +..... +``` + +### 12.只读事务 + +表示在事务中执行的是一些只读操作,如查询,但不会做insert、update、delete操作 + +```sql +start transaction read only; +``` + +### 13.更新丢失 + +丢失更新就是两个不同的事务(或者Java程序线程)在某一时刻对同一数据进行读取后,先后进行修改。导致第一次操作数据丢失。 + +(1)第一类丢失更新 :A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改时失败然后回滚,把A更新的数据也回滚了。(事务撤销造成的撤销丢失) + +(2)第二类丢失更新:A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改并且提交,把A提交的数据给覆盖了。(事务提交造成的覆盖丢失) + +### 14.脏读 + +一个事务在执行的过程中读取到了其他事务还没有提交的数据。 \ No newline at end of file