个人学习记录,供以后回顾和复习
ubuntu下安装使用
参考文章:传送
进入mysql用命令 mysq -u root -p(密码)
注意p和密码之间没有空格
1.DDL,DML,DQL,DCL
sql可以单行或者多行,以分号结尾,可以用空格和缩进来增强可读性,也不区分大小写 。
单行注释:-- 内容,或者# 内容
多行注释:/* 内容 */
DDL
数据库
show databases;
select database();
create database 数据库名;
create database [if not exists] 数据库名 [default charset 字符集] [collate 排序规则];#不存在某某数据库,就创建
drop database [if exists] 数据库名;
use 数据库名;
实操:
每一个sql语句都要写分号,不然系统默认还没结束只是转行
create database itheima default charset utf8mb4;
创建itheima数据库,默认是utf8mb4的字符集,尽量不用utf8,因为他只有3个字节。
表
show tables;#先用use
desc 表名;
show create table 表名;#查询指定标的建表语句
#表的创建
create table 表名{
字段1 字段1类型{comment 字段1注释},
字段2 字段2类型{comment 字段2注释},
....
字段n 字段n类型{comment 字段n注释}
}{comment 表注释};
创建表举例:
eg1
eg2
表的修改以及删除:
alter table 表名 add 字段名 类型(长度) [comment 注释] [约束];#添加字段
alter table 表名 modify 字段名 新数据类型(长度);#修改数据类型
alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释] [约束];#修改字
段名和字段类型
alter table 表名 drop 字段名 # 删除字段名
alter table 表名 rename(to) 新表名 # 修改表名,可以不加to也能修改
drop table [if exists] 表名;#删除表
truncate table 表名;#清空表
create table new_table_name select * from old_table_name; # 复制表结构及数据
#复制表结构到新表,不复制数据
create table new_table_name select * from old_table_name where 1 = 2;
#或
create table new_table_name like old_table_name;
操作:
#添加一行nickname到emp表中
alter table emp add nickname varchar(20) comment '昵称';
#修改nickname字段名以及他的类型
alter table emp change nickname username varchar(30) comment '用户名';
#删除字段
alter table emp drop username
#更改表名
alter tale emp rename to employee
#删除表
drop table if exists tb_user;
#清空表
truncate table employee;
DML
主要是对数据记录的增删改
增
1.给指定字段添加数据
insert into 表名(字段名1, 字段名2, ......) values (值1, 值2, ......);
insert into employee(id, workno, name, gender, age, idcard, entrydate)
VALUES (1, '1', 'Itcast', '男', 10, '123412341234123412', '2022-09-18');
2.未指定字段名,则是给全部字段添加数据
insert into 表名 values(值1,值2,...);
insert into employee values (2, '2', 'Itcast', '男', 10,
'123412348234123412', '2022-09-17');
3.批量添加
#不想一段一段来,一次性添加多段
insert into employee values (....), (.....).....;
#模仿2,后面跟着多段,用逗号分开
改
#修改id为1的数据,将name改为itheima
update employee set name = 'itheima' where id = 1;
#修改id为1的数据,将name改为小昭,gender改为女
update employee set name = '小昭',gender = '女' where id = 1;
#所有员工入职日期改为2008-01-01
update employee set entrydate = '2008-01-01';
删
delete from 表名 where 条件
delete from employee where gender = '女';
delete from employee;
DQL
顺序:select->from->where->group by->having->order by->limit
基本查询:select,from
条件查询:where,having
聚合函数:count,max,min,avg,sum(null不会参与)
分组查询:group by
排序查询:order by
分页查询:limit
条件查询
关键字 | 含义 |
---|---|
>,>=,<,<=,= | 大于,大于等于,小于,小于等于,等于 |
<>,!= | 不等于 |
between…and | 在某个范围之内(中间最小、and后大值) |
in(…) | 在in之后的列表中的值,多选一 |
like | 占位符,模糊匹配,_匹配单个字符,&匹配任意个 |
is null | 是null |
and或&& | 并且 |
or或II | 或者 |
not或者! | 不是 |
select * from 'order'; # 关键字重名时使用
select * from emp where age in (15, 20, 70); # age = 15 or age = 20 or age = 70是一个意思
select * from emp where name like '__';#两个下划线
select * from emp where idcard like '%x';#身份证号最后一位是x的员工信息
分组查询
select 字段列表 from 表名 where 条件 group by 分组字段名 havin 分组后过滤条件
where不能对聚合函数进行判断,而having可以!
- 执行顺序:where > 聚合函数 > having
- 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
#根据性别分组,统计男员工和女员工的数量
select gender,count(*) from emp group by gender
#根据性别分组,统计男性员工和女性员工的平均年龄
select gender,avg(age) from emp group by gender
#查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select workaddress,count(*) from where age < 45 group by workaddress having count(*) >= 3;
排序查询
select 字段列表 from 表名 order by 字段1 排序方式1 字段2 排序方式2
支持多字段排序!
asc升序(默认),desc降序
#根据年龄对公司的员工进行升序排序
select * from emp order by age asc;
#根据年龄对公司的员工进行升序排序,年龄相同,再按照入职时间进行降序排序
select * from emp order by age asc,entrydate desc;
分页查询
select 字段列表 from 表名 limit 起始索引,查询记录数
起始索引从0开始,
起始索引=(查询页码-1)*每页显示记录数
#查询第1页的员工数据,每页展示10条
select * from emp limit 0,10;
#查询第2页的员工数据,每页展示10条记录
select * from emp limit 10,10;
案例练习
1.查询年龄为20,21,22,23岁的员工信息
select * from emp where gender = '女' and age in(20, 21, 22, 23);
2.查询性别为男,并且年龄在20-40岁以内的姓名为三个字的员工
select * from emp where gender = '男' and age between 20 and 40 and name like '___';
3.统计员工表中,年龄小于60的,男性员工和女性员工的人数
select gender, count(*) from emp where age < 60 group by gender
4.查询所有年龄小于等于35岁员工的姓名和年龄,并对查询结果按年龄升序排序,如果年龄相同按入职时间降序排序
select name, age from emp where age <= 35 order by age asc, entrydate desc;
5.查询所有性别为男,且年龄在20-40内的前5个员工信息,对查询结果按照年龄升序排序,年龄相同的按照入职时间降序排序
select * from emp where gender = ‘男’ and age between 20 and 40 order by age asc, entrydate desc limit 5;
DQL执行顺序:from->where->group by->select->order by->limit
所以在from中给表起了别名的话,在后序中可以直接使用别名
select name,age from emp e where age > 15 order by age asc;
DCL
用来管理数据库 用户、控制数据库访问权限
管理用户
1. 查询用户
use mysql;
select * from user;
2. 创建用户
create user '用户名'@'主机名' identified by '密码';
3. 修改用户密码
alter user '用户名'@'主机名' identified with mysql_native_password by '新密码';
4. 删除用户
drop user '用户名'@'主机名';
具体操作:
# 创建用户itcast,只能够在当前主机localhost访问,密码123456
create user 'itcast'@'localhost' identified by '123456';
# 创建用户heima,可以在任意主机访问该数据库,密码123456
create user 'heima'@'%' identified by '123456';
# 修改用户heima的访问密码为1234
alter user 'heima'@'%' identified with mysql_native_password by '1234';
# 删除itcast@localhost用户
drop user 'itcast'@'localhost';
权限控制
1. 查询权限
show grants for '用户名'@'主机名';
2. 授予权限
grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
3. 撤销权限
revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
具体操作:
#查询权限
show grants for 'heima'@'%';
#授予权限
grant all on itcast.* to 'heima'@'%';
#撤销权限
revoke all on itcast.* from 'heima'@'%';
tips:
多个权限之间,使用逗号进行分隔
授权时,数据库名和表名可以使用*进行通配,代表所有
2.函数
字符串函数
演示:
select concat('Hello','MySQL');#HelloMySQL
select lower('Hello');#hello
select upper('Hello');#HELLO
select lpad('01',5,'-');#---01
select rpad('01',5,'-');#01---
select trim(' Hello MySQL ');#Hello MySQL
select substring('Hello MySQL',1,5)#Hello
操作:
#由于业务需求变更,企业员工的工号,统一为5位数,目前不足5位数的全部在前面补0
update emp from workno = lpad(workno,5,‘0’);
数值函数
演示:
select ceil(1.1)#2
select floor(1.9)#1
select mod(3,4)#3
select rand()#0~1之间的随机数
select round(2.345,2)#2.35
实操:
#根据数据库的函数,生成一个六位数的随机验证码
select lpad(round(rand() * 1000000,0),6,‘0’)
#0~1之间的数字小数点移6位
#保留0个小数
#lpad在不足的情况下前面补0
日期函数
演示:
select curdate();#本机获取当前日期
select curtime();#本机获取当前时间
select now();#年月日时分秒
select year(now())
select month(now())
select day(now())
select date_add(now(),interval 70 day) #当前时间往后推70天
select datediff('2021-12-01','2021-11-01')#30
实操:
#查询所有员工入职天数,并根据入职天数倒序排列
select name,datediff(curdate(),entrydate) as 'entrydays' from emp order by entrydays desc;
流程函数
演示:
select if(true,'OK','ERROR')#OK
select ifnull('OK','Default')#OK,' '也可以返回,只有null不返回
操作:
1.
# 查询emp表的员工姓名和工作地址(北京---->一线城市,其他---->二线城市)
select
name,
(case workaddress when '北京' then '一线城市' when '上海' then '一线城市' else '二线城市' end) as '工作地址'
from emp;
2.
# 统计班级各个学员的成绩,展示的规则如下:
# >= 85展示优秀;>=60展示及格;否则展示不及格
select
id,
name,
case when math >= 85 then '优秀' when math >= 60 then '及格' else '不及格' end) '数学',
case when english >= 85 then '优秀' when english >= 60 then '及格' else '不及格' end) '英语',
case when chinese >= 85 then '优秀' when chinese >= 60 then '及格' else '不及格' end) '语文'
from score;
3.约束
演示:
根据需求,完成表结构的创建:
create table user(
id int primary key auto_increment comment '主键',
name varchar(10) not null unique comment '姓名',
age int check(age > 0 && age <= 120) comment '年龄',
status char(1) default '1' comment '状态',
gender char(1) comment '性别'
} comment '用户表';
-------------------------------插入数据
insert into user(name, age, status, gender) values('Tom1', 19, '1', '男'),('Tom2', 25, '0', '男');
insert into user(name, age, status, gender) values('Tom3', 19, '1', '男');
结果:
外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
1.添加外键
#方式1
create table 表名(
字段名 数据类型,
....
[constraint] [外键名称] foreign key(外键字段名) references 主表(主表列名)
);
#方式2
alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名);
2.删除外键
alter table emp drop foreign key fk_emp_dept_id;
外键的删除/更新行为:
#on update在更新时怎么操作,on delete在删除时怎么操作
alter table 表名 add constraint 外键名称 foreign key (外键字段) references 主表名(主表字段名) on update cascade on delete cascade;
4.多表查询
多表关系
一对多:部门和员工,一个员工属于一个部门,一个部门有多个员工;
- 在多的一方建立外键,指向一的一方。
多对多:学生与课程,一个学生可以选择多门课,一门课可以被多个学生选择
- 建立一张中间表,至少包含两个外键,分别关联两方主键
#中间表
create table student_course(
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references student (id),
) comment '学生课程中间表';
结果:
一对一:用户对用户。多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率。
- 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的UNIQUE
# 有一个单表users
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100),
phone VARCHAR(15),
address VARCHAR(255),
bio TEXT
);
users 存储了用户的基本信息(username,email)和详情信息(phone,address,bio),现在决定将这个表拆分成两个表:
- users_basic表,存储用户的基本信息。
- users_details表,存储用户的详细信息。
#创建基本信息表
CREATE TABLE users_basic (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
#创建详细信息表
CREATE TABLE users_details (
user_id INT PRIMARY KEY,
phone VARCHAR(15),
address VARCHAR(255),
bio TEXT,
FOREIGN KEY (user_id) REFERENCES users_basic(id)
);
users_details表中的user_id字段是外键,引用了users_basic表中的id字段,从而建立一对一的关系,每个用户在 users_basic 表和 users_details 表中只能有一条对应记录。
#进行多表查询
SELECT
b.id,
b.username,
b.email,
d.phone,
d.address,
d.bio
FROM
users_basic b
LEFT JOIN
users_details d
ON
b.id = d.user_id;
通过 LEFT JOIN,我们可以查询出 users_basic 和 users_details 表中的对应信息,这样实现了将单表拆分为多表后的数据获取。
内连接
查询的是两张表交集的数据:
- 隐式内连接
select 字段列表 from 表1,表2 where 条件…
#查询每个员工的姓名,以及关联的部门的名称(隐式内连接实现)
#表结构 emp,dept
#连接条件 emp.dept_id == dept.id
select emp.name,dept.name from emp,dept where emp.dept_id = dept.id;
select e.name,d.name from emp e,dept d where e.dept_id = d.id;
- 显示内连接
select 字段列表 from 表1 [inner] join 表2 on 连接条件
#查询每个员工的姓名,以及关联的部门的名称(隐式内连接实现)
#表结构 emp,dept
#连接条件 emp.dept_id == dept.id
select e.name,d.name from emp e inner join dept d on e.dept_id = d.id;
外连接
- 左外连接
查询左表的所有数据,包含表1和表2交集部分的数据
select 字段列表 from 表1 left [outer] join 表2 on 条件…
- 右外连接
查询右表的所有数据,包含表1和表2交集部分的数据
select 字段列表 from 表1 right [outer] join 表2 on 条件…
外连接演示:
#查询emp表的所有数据,和对应部门信息(左外连接)
select e.*,d.name from emp e left outer join dept d on e.dept_id = d.id;
#查询dept表的所有数据,和对应的员工信息(右外连接)
select d.*,e.* from emp e right outer join dept d on e.dept_id = d.id;
自连接
自连接查询语法:
select 字段列表 from 表A 别名A join 表A 别名B on 条件…
演示:
- 查询员工 及其 所属领导的名字
emp表中有id,name,managerid,其中managerid的id指的是领导的id,领导id对应的name就是领导的name
所以不要把这个表看做一个表,同一个表看做两个表,一个是员工表,一个是领导表,员工表的managerid对应的就是领导表的主键id
select a.name,b.name from emp a,emp b where a.managerid = b.id;
联合查询union
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集
语法:
select 字段列表 from 表A
union[all]
select 字段列表 from 表B
其中:对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致!union all 会将全部的数据直接合并在一起,union 会对合并后的数据去重。
# 将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来
select * from emp where salary < 5000
union all
select * from emp where age > 50
union 和 or 的区别:如果某一行同时满足 salary < 5000 和 age > 50,or 的话,它会返回一次;而union all合并多个查询的结果集,而不会去除重复的行。如果某一行满足两个条件,则会返回多次(因为 UNION ALL 不去重)。如果使用union也想去重的话,可以只写union,不写all
子查询
sql中嵌套select语句,称为嵌套查询,又称子查询。比如:
子查询外部的语句可以是insert/update/delete/select的任何一个。
根据子查询的结果不同,分为:
- 标量子查询,子查询结果为单个值
- 列子查询,子查询结果为一列
- 行子查询,子查询结果为一行
- 表子查询,子查询结果为多行多列
标量子查询
返回的是单个值,最简单形式
查询销售部的所有员工信息:
a.首先要查销售部id
select id from dept where name = '销售部';#4
b.然后根据销售部部门id查询员工信息
select * from emp where dept_id = 4;
a+b:
select * from emp where dept_id = (select id from dept where name = '销售部');
列子查询
返回的是一列,也可以是多行
查询销售部和市场部的所有员工信息
a. 查询销售部和市场部的id
select id from dept where name = '销售部' or name = '市场部';#2,4
b. 根据部门id,查询员工信息
select * from emp where dept_id in (2,4);
a+b:
select * from emp where dept_id in (select id from dept where name = '销售部' or name = '市场部');
查询比财务部所有人工资都高的员工信息
a. 查询比财务部所有人工资都高的员工信息
select salary from emp where dept_id = (select id from dept where name = '财务部');
b. 比财务部所有人工资都高的员工信息
select * from emp where salary > all (select salary from emp where dept_id = (select id from dept where name = '财务部'));
比研发部其中任意一人工资高的员工信息
a. 查询研发部所有人工资
select salary from emp where dept_id = (select id from dept where name = '研发部');
b. 比研发部任意一人工资高的员工信息
select * from emp where salary > any(select salary from emp where dept_id = (select id from dept where name = '研发部'));
上面的any也可以换成some,效果一样
行子查询
可以是一行多列
查询与张无忌的薪资及直属领导相同的员工信息
a. 查询张无忌的薪资及其直属领导
select salary,managerid from emp where name = '张无忌';#12500,1
b. 查询与张无忌的薪资及直属领导相同的员工信息
select * from emp where salary = 12500 and managerid = 1;
a+b:
select * from emp where (salary,managerid) = (select salary,managerid from emp where name = '张无忌')
表子查询
返回多行多列
查询与鹿杖客,宋远桥的职位和薪资相同的员工信息
a. 查询鹿杖客,宋远桥的职位和薪资
select job,salary from emp where name = '鹿杖客' or name = '宋远桥';
b. 查询鹿杖客,宋远桥的职位和薪资相同的员工信息
select * from emp (job,salary) in (select job,salary from emp where name = '鹿杖客' or name = '宋远桥');
查询入职日期是2006-01-01之后的员工信息,及其部门信息
a. 入职日期是2006-01-01之后的员工信息
select * from emp where entrydate > '2006-01-01';
b. 查询这部分员工,对应的部门信息
select * from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id;
案例学习
主要涉及emp表,dept表,还有一个salgrade表,
emp与dept的关系,以及salgrade表:
salgrade表是薪资等级表,里面有薪资等级grade字段,等级对应的最低薪资losal字段,等级对应的最高薪资hisal字段
- 查询员工的姓名,年龄,职位,部门信息
涉及到员工的部门,就会涉及到两个表的连接查询,这个地方涉及的是隐式内连接
select e.name,e.age,e.job,d.name from emp e,dept d where e.dept_id = d.id;
- 查询年龄小于30的员工姓名,年龄,职位,部门信息
显示内连接
select e.name,e.age,e.job,d.name from emp e inner join dept d on e.dept_id = d.id where e.age < 30;
- 查询拥有员工的部门id,部门名称
去重!
select distinct d.id,d.name from emp e,dept d where e.dept_id = d.id;
- 查询所有年龄大于40岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来
select * from emp e left join dept d on e.dept_id = d.id where e.age > 40;
- 查询所有员工的工作等级
emp与salgrade之间没有外键关联,但emp中有salary,从salgrade中通过hisal和losal推测
select e.*,s.grade from emp e,salgrade s where e.salary between s.losal and s.hisal;
- 查询研发部所有员工的信息以及工资等级
涉及了3张表emp,salgrade,dept
连接条件:emp.salary between salgrade.losal and salgrade.hisal,emp.dept_id = dept.id
查询条件:dept.name = ‘研发部’
select e.*,s.grade from emp e,dept d,salgrade s where e.dept_id = d.id and (e.salary between s.losal and s.hisal) and (d.name = '研发部');
- 查询研发部员工的平均工资
涉及到2张表
select avg(e.salary) from emp e,dept d where e.dept_id = d.id and d.name = '研发部';
- 查询工作比“灭绝”高的员工信息
select * from emp where salary > (select salary from emp where name = '灭绝');
- 查询比平均薪资高的员工信息
select * from emp where salary > (select avg(salary) from emp);
- 查询低于本部门平均工资的员工信息
查询指定部门的平均薪资:select avg(e1.salary) from emp e1 where e1.dept_id = 1;
查询本部门:一张表变成两张就行,当前部门的平均工资用e1来计算,查询的员工用e2表
select * from emp e2 where e2.salary < (select avg(e1.salary) from emp e1 where e1.dept_id = e2.dept_id);
- 查询所有的部门信息,并统计部门的员工人数
统计指定部门的员工数量:select count(*) from emp where dept_id = 1
查看部门的人数信息:select d.id,d.name,(select count(*) from emp e where e.dept_id = d.id) '人数' from dept d
select d.id,d.name,(select count(*) from emp e where e.dept_id = d.id) '人数' from dept d;
- 查询所有学生的选课情况,展示出学生名称,学号,课程名称
涉及表:student,course,student_course
连接条件:student.id = student_course.studentid,course.id = student_course.courseid
select s.name,s.no,c.name from student s,student_course sc,course c where s.id = sc.studentid and sc.courseid = c.id;
5.事务
事务是一组操作的集合,它是一个不可分割的工作单位,事物会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
事务操作
转账操作(张三给李四转账1000)
1. 查询张三账户余额
select * from account where name = '张三';
2. 将张三账户余额-1000
update account set money = money - 1000 where name = '张三';
3. 将李四账户余额+1000
update account set money = money + 1000 where name = '李四';
123都是事物,是自动执行的,如果中间有异常,就会失败,所以需要考虑改变事物的方式:
# 方式一
#查看事务提交方式
SELECT @@AUTOCOMMIT;
#设置事务提交方式,1为自动提交,0为手动提交,该设置只对当前会话有效
SET @@AUTOCOMMIT = 0;
#此时为手动提交
#提交事务
COMMIT;
#一开始没执行提交时是没有反应的,执行了提交,才会有下一步
#一旦出错
#回滚事务
ROLLBACK;
方式1:给转账操作添加手动事务
select @@autocommit;# 1
set @@autocommit = 0;
---转账操作
1. 查询张三账户余额
select * from account where name = '张三';
2. 将张三账户余额-1000
update account set money = money - 1000 where name = '张三';
3. 将李四账户余额+1000
update account set money = money + 1000 where name = '李四';
---提交事务
commit;
---回滚事务
rollback;
方式2
开启事务
start transaction 或 begin;
提交事务
commit;
回滚事务
rollback;
自动提交的事务方式:
set @@autocommit = 1;
#自动提交
select @@autocommit;
#开启事务
start transaction;
---转账操作
1. 查询张三账户余额
select * from account where name = '张三';
2. 将张三账户余额-1000
update account set money = money - 1000 where name = '张三';
3. 将李四账户余额+1000
update account set money = money + 1000 where name = '李四';
---提交事务
commit;
---回滚事务
rollback;
事务四大特性
这里涉及面试题:原子性;一致性;隔离性;持久性
原子性:事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
一致性:事务完成时,必须使所有的数据都保持一致状态
隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性:事务一旦提交或者回滚,它对数据库中的改变就是永久的。
并发事务问题
A事务和B事务同时操作数据库会引发的问题
事务隔离级别
用来解决并发事务问题的
4种事务的隔离级别,×是在这种级别下可以解决
---查看事务隔离级别
select @@transaction_isolation;
---设置事务隔离级别
set [session|global] transaction isolation level {read uncommitted|read committed|repeatable read|serializable}
演示一下:
---查询事务隔离级别
select @@transaction_isolation;# repeatable read
---设置事务隔离级别
set session transaction isolation level read uncommitted;
set session transaction isolation level repeatable read;
开启2个终端窗口,相当于2个事务,切换到同一个数据库,演示第一个脏读问题:
窗口A:
设置了事务隔离级别是read uncommitted,它可以出现脏读问题
窗口B:
给张三减了1000
接下来看看窗口A:
张三的钱从2000减到了1000
以上就是脏读,因为窗口B执行的操作根本没有提交,事务开启了,它commit了吗?没有!所以read uncommitted是可以出现脏读问题的!
接下来将事务的隔离级别改成read committed
接下来脏读问题就会消失