主要内容
- 本文主要针对mysql的一些初级知识,包括mysql的一些基础操作,mysql中的一些函数及聚合函数的用法,mysql中的一些多表查询、约束介绍,以及mysql中事务的简单介绍;
- 本文可用作一些常见SQL语句编写格式的查找,起到一个类似于“字典的作用”。
1. mysql常见命令:
- 启动、停止msql服务
1. net start mysql服务名称
2. net stop mysql服务名称
- mysql数据库连接
mysql [-h 127.0.0.1][-P 3306] -u root -p 密码 #[]里边内容为可选项
2. SQL分类:
分类 | 全称 | 说明 |
---|---|---|
DDL | Data Definition Language | 数据定义语言,用来定义数据库对象(数据库、表、字段) |
DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改 |
DQL | Data Query Language | 数据查询语言,用来查询数据库中表的记录 |
DCL | Data Control Language | 数据控制语言,用来创建数据库用户、控制数据库的访问权限 |
2.1 表结构常见字段数据类型介绍:
- 数值类型:
注意:DECIMAL类型中的M指的是一共有几位数字,D指的是小数点后边有几位;
- 日期类型:
- 字符串类型:
2.2 DDL: 数据库、表、字段操作;
2.2.1 数据库操作:
- 创建数据库:
create database [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则];
- 查询所有数据库:
SHOW DATABASES;
- 查询当前数据库:
SELECT DATABASE();
- 删除数据库:
DROP DATABASE [IF EXISTS] 数据库名;
- 使用数据库:
USE 数据库名;
2.2.2 表操作:
- 查询当前数据库所有表:
SHOW TABLES;
- 查询表结构:
DESC 表名;
- 查询指定表的建表语句:
SHOW CREATE TABLE 表名;
- 修改表名:
ALTER TABLE 表名 RENAME TO 新表名;
#例:将user表改名为emp
ALTER TABLE user RENAME TO emp;
- 删除表:
DROP TABLE [IF EXISTS] 表名;
- 删除指定表,并重新创建表结构:
TRUNCATE TABLE 表名;
2.2.3 字段操作:
- 给表添加字段:
ALTER TABLE 表名 ADD 字段名 类型(长度)[COMMENT 注释] [约束];
#例:为user表添加一个新的字段“sex”,类型为char(1);
ALTER TABLE user ADD sex char(1) COMMENT '性别';
- 修改数据类型:
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
#例:将user表中的sex字段类型修改为varchar(1);
ALTER TABLE user MODIFY sex varchar(1);
- 修改字段名与字段类型:
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度)[COMMENT 注释] [约束];
#例:将user表的sex修改为gender,类型为char(1)
ALTER TABLE user CHANGE sex gender char(1) COMMENT '性别';
- 删除字段:
ALTER TABLE 表名 DROP 字段名;
#例:去掉user表的gender字段;
ALTER TABLE user DROP gender;
2.3 DML :表数据操作;
2.3.1 添加数据:
- 给指定字段添加数据:
INSERT INTO 表名(字段名1,字段名2,...) VALUES (值1,值2,...);
#例:给user表中的name、gender字段添加数据;
INSERT INTO user(name,gender) VALUES ('李白','男'),('杜甫','男');
- 给全部字段添加数据
INSERT INTO 表名 VALUES (值1,值2,...); #注意:值的顺序要与表中字段的顺序相同
#例:给user表中的字段添加数据;
INSERT INTO user VALUES (1,'李白','男'),(2,'杜甫','男');
2.3.2 修改数据:
注意:修改语句在添加条件的时候会修改满足条件的数据,如果不添加条件会修改整张表的数据;
UPDATE 表名 set 字段名1=值1,字段名2=值2,... [WHERE 条件];
#例:将user表中李白得性别修改为女;
UPDATE user set gender = '女' WHERE name = '李白';
2.3.3 删除数据:
注意: 删除语句在添加条件的时候会修改满足条件的数据,如果不添加条件会删除整张表的数据;
DELETE FROM 表名 [WHERE 条件]
#例:删除user表中的gender=女的数据;
DELETE FROM user where gender = '女';
2.4 DQL
2.4.1 基本语法:
SELECT 字段列表 FROM 表名列表 WHERE 条件列表 GROUP BY 分组字段列表 HAVING 分组后条件列表 ORDER BY 排序字段列表 LIMIT 分页参数;
2.4.2 基本查询:
- 查询多个字段:
# 方式一:推荐
SELECT 字段1、字段2、... FROM 表名;
# 方式二:不推荐
SELECT * FROM 表名; #查询出全部的字段数据
- 设置别名:
SELECT 字段1 [AS 别名],字段2 [AS 别名2] ... FROM 表名; #其中使用的时候AS可以省略
#例:
select name n, gender g from user;
- 去除重复记录:
SELECT DISTINCT 字段列表 from 表名; #关键字DISTINCT用来去重使用;
2.4.3 条件查询:WHERE
SELECT 字端列表 FROM 表名 WHERE 条件列表;
#例:
select * from emp where idcard like '%x'; #匹配身份证号码最后一位是x的数据
select * from emp where name like '——'; #匹配姓名为两个字的员工信息
select * from emp where age in(19,20,60); #匹配年龄为19或20或40的人员数据
select * from emp where age between 20 and 60; #匹配年龄在20到60的人员数据
select * from emp where idcard is null; #匹配没有身份证号码的人员数据,匹配有数据的就是is not null;
- 条件介绍:
比较运算符 | 功能 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
= | 等于 |
<> 或 != | 不等于 |
BETWEEN …AND… | 在某个范围内(包含最小、最大值) |
IN(…) | 在in之后的列表中的值,多选一 |
LIKE 占位符 | 模糊匹配(_匹配单个字符,%匹配任意个字符) |
IS NULL | 是NULL |
逻辑运算符 | |
AND 或 && | 并且(多个条件同时成立) |
OR 或 || | 或者(多个条件满足其一) |
NOT 或! | 非,不是 |
2.4.4 聚合函数:count、max、min、avg、sum
# count:统计某个字段的次数
select count(*) from user; #查询user表中的用户数量
# max:统计某个字段在表中的最大值
select max(age) from user; #查询user表中年龄最大的用户
# min:统计某个字段在表中的最小值
select min(age) from user; #查询user表中年龄最小的用户
# avg:统计某个字段数据的平均值
select avg(age) from user; #查询user表中用户的平均年龄
# sum:统计某个字段数据的总和
select sum(age) from user; #查询user表中用户的年龄总和
2.4.5 分组查询:GROUP BY
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组过滤条件]
# 例:查询年龄小于35的员工,按照工作地址进行分组,获取员工数量大于等于3的工作地址;
select workaddress,count(*) addr_count from emp where age <35 group by workaddress having addr_count >= 3;
-
where 与 having的区别:
- 执行时机不同:where是在分组之前进行过滤,不满足where条件的数据不会参加分组;而having是在分组之后对结果进行过滤。
- 判断条件不同:where不能对聚合函数进行判断,而having可以;
-
注意事项:
- 执行顺序:where > 聚合函数 > having
- 分组之后,查询的条件一般为聚合函数和分组字段,查询其他字段没有任何的意义;
2.4.6 排序查询:ORDER BY
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;
# ASC 表示升序排序,默认,desc 表示降序排序;
#例:根据年龄对员工进行升序排序,年龄相同的在按照入职时间进行降序排序,
select * from emp order by age asc, entrydate desc; #注意多字段情况下当前边的字段值相同是才会按照后边的排序方式进行排序;
2.4.7 分页查询:LIMIT
SELECT 字段列表 FROM 表名 LINIT 起始索引,查询记录数;
#例:查询user表第一页数据,每页展示10条数据;
select * from user limit 0,10;
##### 比较复杂一点的sql示例;
select * from emp where gender = '女' and between 20 and 40 order by age asc, entrydate desc limit 0,10;
-
注意:
- 起始索引是从0开始的,起始索引 = (查询页码 - 1)* 每页显示记录数;
- 分页查询是数据库的方言,不同的数据库实现不同,mysql是limit;
- 如果查询的是第一页的数据,起始索引可以省略,之间简写为limit 10;
-
DQL执行顺序:
FROM > WHERE > GROUP BY > SELECT > ORDER BY > LIMIT
2.5 DCL
2.5.1 管理用户:
- 查询用户:
USE mysql;
SELECT * FROM user;
- 创建用户:
CREATE USER '用户名@主机名' IDENTIFIED BY '密码';
#例: 创建用户test,只能在当前主机本地访问,密码是123456
CREATE USER 'test@localhost' IDENTIFIED BY '123456';
- 修改用户密码:
ALTER USER '用户名@主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
- 删除用户:
DROP USER '用户名@主机名';
# 例:删除test用户
DROP USER 'test@localhost';
- 注意:
- 主机名可以用%通配,当使用%的时候就代表所有的主机都可以访问
2.5.2 权限控制:
- 查询权限:
SHOW GRANTS FOR '用户名@主机名'
- 授予权限:
GRANT 权限列表 ON 数据库名.表名 TO '用户名@主机名';
#权限列表:
ALL,ALL PRIVILEGES #所有权限
SELECT #查询数据
INSERT #插入数据
UPDATE #修改数据
DELETE #删除数据
ALTER #修改表
DROP #删除数据库/表/视图
CREATE #创建数据库/表
- 撤销权限:
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名@主机名';
- 注意:
- 当授予多个权限时,多个权限之间用逗号分割;
- 授权时,数据库名与表名可以使用*进行通配,代表所有;
3. 函数:
函数是指一段可以直接被另一端程序调用的程序或代码;
分类:
3.1 字符串函数:
函数 | 功能 |
---|---|
CONCAT(S1,S2,…,Sn) | 字符串拼接,将S1,S2,…,Sn拼接成一个字符串 |
LOWER(str) | 将字符串str全部转为小写 |
UPPER(str) | 将字符串str全部转为大写 |
LAPD(str,n,pad) | 左填充,用字符串pad对str的左边进行填充,达到n个字符串长度 |
RPAD(str,n,pad) | 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度 |
TRIM(str) | 去掉字符串头部和尾部的空格 |
SUBSTRING(str,start,len) | 返回从字符串str从start位置起的len个长度的字符串 |
# 示例:
update emp set workno = lpad(workno,5,'0'); #统一将员工工号修改为5位,不足的在前边补0;
3.2 数值函数:
函数 | 功能 |
---|---|
CEIL(x) | 向上取整 |
FLOOR(x) | 向下取整 |
MOD(x,y) | 返回x/y的模 |
RAND() | 返回0~1之间的随机数 |
ROUND(x,y) | 求参数四舍五入的值,保留y位小数 |
# 示例:
select lpad(round(rand()*1000000,0),6,0); #通过数据库函数生成一个六位数的随机验证码;
3.3 日期函数:
函数 | 功能 |
---|---|
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前日期与时间 |
YEAR(date) | 返回指定date的年份 |
MONTH(date) | 返回指定date的月份 |
DAY(date) | 返回指定date的日期 |
DATE_ADD(date,INTERVAL expr type) | 返回一个日期/时间值加上一个时间间隔expr之后的时间值 |
DATEDIFF(date1,date2) | 返回起始时间date1和结束时间date2之间的天数 |
# 示例:
select name,datediff(curdate(),entrydate) as 'entrydays' from emp order by entrydays desc; #查询员工入职天数,并根据入职天数倒序排序,其中entrydate为入职日期;
3.4 流程函数:
函数 | 功能 |
---|---|
IF(value,t,f) | 如果value为true,则返回t,否则返回f |
IFNULL(value1,value2) | 如果value1不为空,返回value1,否则返回value2 |
CASE WHEN [val1] THEN [res1] … ELSE [default] END | 如果val1为true,返回res1,…否则返回default默认值 |
CASE [expr] WHEN [val1] THEN [res1] … ELSE [default] END | 如果expr的值等于val1,返回res1,…否则返回default默认值 |
#示例:查询emp表中的员工姓名和工作地址(北京/上海--->一线城市,其他--->二线城市)
select name (case workaddress when '北京' then '一线城市' when '上海' then '一线城市' else '二线城市' end) as '工作地址' from emp;
#示例二:查询学生的成绩,成绩大于等于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;
4. 约束:
- 约束就是作用于表中字段上的规则,用于限制存储在表中的数据;
- 目的就是保证数据库中数据的正确性、有效性与完整性;
- 可以在创建表或者修改表的时候添加约束;
约束 | 描述 | 关键字 |
---|---|---|
非空约束 | 限制该字段的数据不能为null | NOT NULL |
唯一约束 | 保证该字段的所有数据都是唯一、不重复的 | UNIQUE |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | PRIMARY KEY |
默认约束 | 保存数据的时候,如果未指定该字段的值,则采用默认值 | DEFAULT |
检查约束(8.0.16版本之后) | 保证字段值满足某一个条件 | CHECK |
外键约束 | 用来将两张表的数据之间建立联系,保证数据的一致性和完整性 | FOREIGN KEY |
自增 | 常搭配主键一起使用,将数值每次加1 | AUTO_INCREMENT |
# CHECK约束示例:
age int check(age > 0 && age <= 120) comment '年龄'; #限制年龄的值在0~120之间
#给表添加外键示例一:创建表时添加
CREATE TABLE 表名(
字段名 数据类型 约束,
...
[CONSTRAINT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名));
#给表添加外键示例二:修改表时添加
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名);
#例:
alter table emp add constraint emp_dept_id_fk foreign key (dept_id) references dept(id);
#删除外键:使用drop关键字对表进行修改,emp_dept_id_fk是外键的别名;
alter table emp drop foreign key emp_dept_id_fk;
外键约束:
行为 | 说明 |
---|---|
NO ACTION | 当在父表中删除/更新对应记录的时候,首先检查该记录是否有外键,如果有则不允许删除/更新。(与RESTRICT一致) |
RESTRICT | 当在父表中删除/更新对应记录的时候,首先检查该记录是否有外键,如果有则不允许删除/更新。(与NO ACTION一致) |
CASCADE | 当在父表中删除/更新对应记录的时候,首先检查该记录是否有外键,如果有则同时删除/更新外键在子表中的数据 |
SET NULL | 当在父表中删除对应记录的时候,首先检查该记录是否有对应外键,如果有则设置子表中该外键的值为null(要求该外键可以为null) |
SET DEFAULT | 父表变更的时候,子表将外键列设置成一个默认的值(Innodb不支持) |
#示例:将字段的更新与删除约束设置为CASCADE
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY(外键字段名) REFERENCES 主表(主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
5. 多表查询:
多表查询值的就是从多张表中查询数据,在多表查询的时候要消除无效的笛卡尔积;
5.1 多表关系:
- 一对一:选择任意一张表建立外键,关联另一张表的主键,并设置外键为唯一;
- 一对多:一般在多的一方建立外键,指向一的一方的主键;
- 多对多:一般建立一张中间表,中间表包含两个外键,分别关联两方主键;
5.2 内连接:
查询的是两张表的交集部分
- 显式内连接:
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件;
#写法示例:
select e.name,d.name from emp e join dept d ON e.dept_id = d.id;
- 隐式内连接
SELECT 字段列表 FROM 表1,表2 WHERE 条件;
#写法示例:
select e.name,d.name from emp e,dept d where e.dept_id = d.id;
5.3 外连接:
- 左外连接:相当于表1(左表)中的全部数据,包含表1和表2交集部分的数据;
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件;
#用法示例:
select e.*, d.name from emp e left join dept d on e.dept_id = d.id;
- 右外连接:相当于表2(右表)中的全部数据,包含表1和表2交集部分的数据;
SELECT 字段列表 FROM 表1 RIGHT OUTER JOIN 表2 ON 条件;
#用法示例:
select e.*, d.* from emp e right outer join dept d on e.dept_id = d.id;
注意: 右外连接在一定情况下可以编写为左外连接,所以我们一般用的都是左外连接的写法;
5.4 自连接:
自连接查询可以是内连接查询,也可以是外连接查询;
**注意:**自连接的时候表名一定要起别名,否则自连接没有任何意义;
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件; #内连接-显式连接写法
----
SELECT 字段列表 FROM 表A 别名A , 表A 别名B WHERE 条件; #内连接-隐式连接写法
----
SELECT 字段列表 FROM 表A 别名A LEFT JOIN 表A 别名B ON 条件; #外连接-左外连接写法
#用法示例: 查询员工表中员工姓名及其领导姓名;managerid为领导id
#内连接-隐式连接写法
select a.name, b.name from emp a, emp b where a.managerid = b.id;
#外连接-左外连接写法
select a.name, b.name from emp a left join emp b on a.managerid = b.id;
5.5 联合查询:
- 联合查询就是将多次查询的结果合并形成一个新的结果集;
- 对于联合查询的多张表必须保持列数相同,字段类型也要保持一致;
- union all会将全部的数据直接合并到一起,不去重;
- union会将数据合并后进行去重;
SELECT 字段列表 FROM 表A ...
UNION [all]
SELECT 字段列表 FROM 表B ...;
#用法示例:
select * from emp where salary < 5000
union all
select * from emp where age >30;
5.5 子查询:
- sql语句中嵌套select语句,称为嵌套查询,又叫子查询;
- 子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT中的任何一个;
SELECT 字段列表 FROM t1 WHERE column1 = (SELECT column1 FROM t2);
5.5.1 按照子查询结果划分:
- 标量子查询:子查询结果为单个值
# 用法示例:查询入职时间是李白入职时间之后的员工信息
select * from emp where entrydate > (select entrydate from emp where name = '李白');
- 列子查询:子查询结果为一列
列子查询常用操作符:
操作符 | 描述 |
---|---|
IN | 在指定的集合范围内,多选一 |
NOT IN | 不在指定的集合范围之内 |
ANY | 子查询返回列表中,有任意一个满足即可 |
SOME | 与ANY等同,用在SOME的地方都可以使用ANY |
ALL | 子查询返回列表的所有值都必须满足 |
# 用法示例:根据部门id查询员工信息
select * from emp where dept_id in (select id from dept where name = '开发部' or name = '市场部');
# 查询比研发部其中任意一人工资高的员工信息
select * from emp where salary > some (select salary from emp where dept_id = (select id from dept where name = '研发部'));
# 查询出与'李白'薪资和直属领导相同的员工信息
select * from emp where (salary,managerid) = (select salary,managerid from emp where name = '李白');
- 行子查询:子查询结果为一行(可以是多行)
- 常见操作符:= 、<>、IN 、NOT IN
# 查询出与'李白'薪资和直属领导相同的员工信息
select * from emp where (salary,managerid) = (select salary,managerid from emp where name = '李白');
- 表子查询:子查询结果为多行多列
- 常见操作符:IN
# 查询出与'李白'或'杜甫'薪资和直属领导相同的员工信息
select * from emp where (salary,managerid) = (select salary,managerid from emp where name in ('李白','杜甫'));
# 示例二:查询入职时间在“2006-01-01”之后的员工以及对应的部门信息
select e.*,d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id;
5.5.2 根据子查询结果划分:
-
WHERE 之后
-
FROM 之后
-
SELECT 之后
6.事务:
6.1 事务简介:
- 事务就是一组操作的集合,是一个不可再分割的单位。事务会将所有的操作作为一个整体 一起向系统提交或者回滚操作请求,也就是说这些操作要么同时成功,要么同时失败;
6.2 事务基本操作:
mysql默认事务是自动提交的,即在执行一条DML语句之后,mysql会立即隐式的提交事务;
- 查看、设置事务提交方式:
SELECT @@autocommit; #查看事务自动提交是否开启,1是开启,0是关闭
SET @@autocommit = 0; #关闭mysql事务自动提交机制
- 提交事务:
COMMIT;
- 回滚事务:
ROLLBACK;
- 开启事务
START TRANSACTION 或 BEGIN;
事务操作的两种方式:
- 第一种就是关闭mysql的事务自动提交机制,然后手动对事务进行提交;但是这种方式的弊端就是每次执行DML语句都需要手动提交,不论语句是不是核心业务语句,比较繁琐;
- 第二种就是开启mysql的事务自动提交,然后在核心业务之前使用语句“START TRANSACTION 或 BEGIN”开启事务,然后业务执行完成之后再手动提交,相比较第一种大大的减少了工作量;
6.3 事务四大特性:
事务的四大特性简写为ACID;
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败;
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态;
- 隔离性(Iolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行;
- 持久性(Durability):事务一旦提交或者回滚,它对数据库中数据的改变就是永久的;
6.4 并发事务问题:
- 脏读:一个事务读取到另一个事务还没有提交的数据。
- 不可重复读:一个事务先后读取同一条记录,但是两次读取到的数据不同,称之为不可重复读。
- 幻读:一个事务按照条件进行查询时,没有对应的数据行,但是在插入数据的时候又发现这行数据存在,就好像出现了“幻影”。
注意:
- 出现不可重复读的原因就是:在事务A查询完毕之后,事务B立马修改了事务A查看的数据并提交,这时候事务A再次查看的时候就会发现两次查看的结果不同,而且这两次查看的期间事务A并没有提交;
- 出现幻读的原因就是:在事务A查询满足某条件的数据时,发现数据不存在,这时候事务B添加了一条满足事务A查询条件的数据,并提交;然后事务A在添加满足查询条件的数据时,发现已经存在一条数据,但是查询的时候由于不存在不可重复读的问题,所以查出来的依旧是一个空的结果,这就导致出现了幻读;
6.5 事务隔离级别:
- 为了解决上述事务并发问题,mysql提供了四种隔离级别的应对方案;
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted(读未提交) | √ | √ | √ |
Read committed(读提交) | × | √ | √ |
Repeatable Read(重复读,默认) | × | × | √ |
Serializable(序列化) | × | × | × |
这四种隔离级别从上到下越来越高,数据越来越安全,但是效率也随着越来越低;
- 查看事务的隔离级别:
SELECT @@TRANSACTION_ISOLATION;
- 设置事务隔离级别:
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
时候事务A再次查看的时候就会发现两次查看的结果不同,而且这两次查看的期间事务A并没有提交;
- 出现幻读的原因就是:在事务A查询满足某条件的数据时,发现数据不存在,这时候事务B添加了一条满足事务A查询条件的数据,并提交;然后事务A在添加满足查询条件的数据时,发现已经存在一条数据,但是查询的时候由于不存在不可重复读的问题,所以查出来的依旧是一个空的结果,这就导致出现了幻读;
6.5 事务隔离级别:
- 为了解决上述事务并发问题,mysql提供了四种隔离级别的应对方案;
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted(读未提交) | √ | √ | √ |
Read committed(读提交) | × | √ | √ |
Repeatable Read(重复读,默认) | × | × | √ |
Serializable(序列化) | × | × | × |
这四种隔离级别从上到下越来越高,数据越来越安全,但是效率也随着越来越低;
- 查看事务的隔离级别:
SELECT @@TRANSACTION_ISOLATION;
- 设置事务隔离级别:
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}