- Published on
SQL 语句学习
- Authors

- Name
- MissTree
SQL
在数据库中,SQL(Structured Query Language)是一种用于管理和操作关系型数据库的标准语言。它提供了一种结构化的方式来查询、更新和管理数据。SQL语句可以用于执行各种操作,包括数据检索、数据插入、数据更新和数据删除。
DQL查询
DQL(Data Query Language)是一种用于查询数据库中数据的语言。它是SQL语言的一个子集,主要用于从数据库中检索数据。DQL语句用于从数据库中检索数据,而不涉及对数据的修改。我们对数据库操作最多的是查询,而不是新增修改。
# 查询多个字段
SELECT column1, column2, ... FROM table_name;
# 查询所有字段
SELECT * FROM table_name;
# 查询指定条件的数据
SELECT column1, column2,... FROM table_name WHERE condition;
# 别名
SELECT column1 AS alias_name, column2 AS alias_name,... FROM table_name;
SELECT column1 alias_name, column2 alias_name,... FROM table_name; # 别名可以省略AS
# 去重
SELECT DISTINCT column1, column2,... FROM table_name;
条件查询
# 等于
SELECT * FROM table_name WHERE column1 = value;
# 不等于
SELECT * FROM table_name WHERE column1 != value;
# 大于
SELECT * FROM table_name WHERE column1 > value;
# 小于
SELECT * FROM table_name WHERE column1 < value;
# 大于等于
SELECT * FROM table_name WHERE column1 >= value;
# 小于等于
SELECT * FROM table_name WHERE column1 <= value;
# between BETWEEN value1 AND value2, value1必须为最小值,value2必须为最大值,否则无法查询结果
SELECT * FROM table_name WHERE column1 BETWEEN value1 AND value2;
# 模糊查询
SELECT * FROM table_name WHERE column1 LIKE '%value%';
# 模糊查询,%表示任意多个字符,_表示任意单个字符
SELECT * FROM table_name WHERE column1 LIKE 'value%';
SELECT * FROM table_name WHERE column1 LIKE '%value';
SELECT * FROM table_name WHERE column1 LIKE '_value';
SELECT * FROM table_name WHERE column1 LIKE 'value_value';
# 多个条件查询
SELECT * FROM table_name WHERE column1 = value1 AND column2 = value2;
SELECT * FROM table_name WHERE column1 = value1 OR column2 = value2;
SELECT * FROM table_name WHERE age = 20 OR age = 18 OR age = 16;
SELECT * FROM table_name WHERE age IN (20,18,16); # IN表示在多个值中
SELECT * FROM table_name WHERE age NOT IN (20,18,16); # NOT IN表示不在多个值中
SELECT * FROM table_name WHERE age BETWEEN 18 AND 20; # BETWEEN表示在两个值之间
SELECT * FROM table_name WHERE age NOT BETWEEN 18 AND 20; # NOT BETWEEN表示不在两个值之间
SELECT * FROM table_name WHERE column1 = value1 AND column2 = value2 OR column3 = value3;
SELECT * FROM table_name WHERE column1 = value1 AND (column2 = value2 OR column3 = value3);
SELECT * FROM table_name WHERE column1 = value1 AND column2 = value2 AND column3 = value3;
聚合函数
聚合函数是一种特殊的函数,它可以对一组数据进行汇总计算。聚合函数通常用于查询数据的统计信息,例如求和、平均值、最大值、最小值等。
# 求和
SELECT SUM(column1) FROM table_name;
# 平均值
SELECT AVG(column1) FROM table_name;
# 最大值
SELECT MAX(column1) FROM table_name;
# 最小值
SELECT MIN(column1) FROM table_name;
# 计数
SELECT COUNT(column1) FROM table_name;
# 计数,不包括NULL值
SELECT COUNT(column1) FROM table_name WHERE column1 IS NOT NULL;
# 计数,包括NULL值
SELECT COUNT(column1) FROM table_name WHERE column1 IS NULL;
# 计数,包括重复值
SELECT COUNT(column1) FROM table_name;
# 计数,不包括重复值
SELECT COUNT(DISTINCT column1) FROM table_name;
# 计数,包括重复值和NULL值
SELECT COUNT(*) FROM table_name;
# 计数,不包括重复值和NULL值
SELECT COUNT(DISTINCT column1) FROM table_name WHERE column1 IS NOT NULL;
# 计数,包括重复值和NULL值
SELECT COUNT(*) FROM table_name WHERE column1 IS NOT NULL;
# 计数,不包括重复值和NULL值
SELECT COUNT(DISTINCT column1) FROM table_name WHERE column1 IS NULL;
在统计聚合函数数量的时候是不统计NULL值的,但是如果想要统计NULL值,可以使用COUNT(*)或者COUNT(1)。
分组查询
分组查询是一种特殊的查询,它可以对一组数据进行分组,并对每个分组进行汇总计算。分组查询通常用于查询数据的统计信息,例如求和、平均值、最大值、最小值等。
SELECT column1, column2,... FROM table_name GROUP BY column1, column2,...;
SELECT column1, column2,... FROM table_name GROUP BY column1, column2,... HAVING condition;
SELECT gender count(*) FROM table_name GROUP BY gender;
# 统计男女性别下的> 35 人数
SELECT gender count(*) FROM table_name GROUP BY gender HAVING count(*) > 35;
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。where和having的区别:
- where是在分组前进行过滤,having是在分组后进行过滤。
- where不能使用聚合函数,having可以使用聚合函数。
- where的执行顺序比having先执行。
排序查询
排序查询是一种特殊的查询,它可以对一组数据进行排序。排序查询通常用于查询数据的统计信息,例如求和、平均值、最大值、最小值等。
SELECT column1, column2,... FROM table_name ORDER BY column1, column2,... ASC|DESC;
SELECT *age.* FROM table_name ORDER BY age ASC|DESC;
# ASC表示升序,DESC表示降序,默认是升序 可以省略ASC
SELECT * FROM table_name ORDER BY age;
# 排序第一个相同的字段,第二个字段排序可以另外设计
SELECT * FROM table_name ORDER BY age, name;
分页查询
分页查询是一种特殊的查询,它可以对一组数据进行分页。分页查询通常用于查询数据的统计信息,例如求和、平均值、最大值、最小值等。
SELECT column1, column2,... FROM table_name LIMIT offset, length;
SELECT column1, column2,... FROM table_name LIMIT length OFFSET offset;
SELECT column1, column2,... FROM table_name LIMIT length;
# 查询第1页,每页10条数据
SELECT * FROM table_name LIMIT 0, 10;
SELECT * FROM table_name LIMIT 10 OFFSET 0;
SELECT * FROM table_name LIMIT 10;
# 查询第2页,每页30条数据 起始索引=(查询页码-1)*每页显示记录数
SELECT * FROM table_name LIMIT 60, 30;
注意
- 起始索引从0开始,起始索引=(查询页码-1)*每页显示记录数
- 分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是UMIT
- 如果查询的是第一页数据,起始索引可以省略,直接简写为imit 10。
- 进行分页时,排序的sql语句必须在limit语句之前。
执行顺序
编写顺序:select -> from -> where -> group by -> having -> order by -> limit 执行顺序:from -> where -> group by -> having -> select -> order by -> limit
SELECT column1, column2,... FROM table_name WHERE condition GROUP BY column1, column2,... HAVING condition ORDER BY column1, column2,... LIMIT offset, length;
# 别名验证 其执行结果都是一样的
select nan,age from enp where age > 15 order by age asc;
select nan,age from enp e where e.age > 15 order by age asc;
select e.nan,e.age from enp e where e.age > 15 order by age asc;
# 解释:
# 1. from enp e 表示从enp表中查询数据,别名e
# 2. where e.age > 15 表示查询年龄大于15的员工
# 下面执行报错 说明select是where前执行的
select e.nan enan,e.age eage from enp e where eage > 15 order by age asc;
# 下面执行成功,说明select是order by前执行的
select e.nan enan,e.age eage from enp e where e.age > 15 order by eage asc;
函数
函数是一种特殊的语句,它可以对一组数据进行计算。函数通常用于查询数据的统计信息,是SQL数据库内置函数。
字符串函数
| 函数 | 功能 |
|---|---|
| CONCAT(S1,S2..Sn) | 字符串3拼接,将S1,S2,….Sn拼接成一个字符串 |
| LOWER(str) | 将字符f串str全部转为小写 |
| UPPER(Str) | 将字符串str全部转为大写 |
| LPAD(str,n,pad) | 左填充,用字符串pad对str的左边进行填充,达到n个字符串长度 |
| RPAD(str,n,pad) | 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度 |
| TRIM(str) | 去掉宇2符串头部和尾部的空格 |
| SUBSTRING(str,start,len) | 返回从字符串str从start位置起的len个长度的字符串 |
# LOWER
SELECT LOWER('Hello World'); # hello world
# UPPER
SELECT UPPER('Hello World'); # HELLO WORLD
# 由于业务变更、企业员工的工号,统一为5位数,目前不足5位数的全部企的围补0。比如:1号员工的工号应读为00001
UPDATE employee SET id = LPAD(id,5,'0');
数值函数
| 函数 | 功能 |
|---|---|
| CEIL(x) | 向上取整 |
| FLOOR(x) | 向下取整 |
| MOD(x,y) | 返回x/y的模(取除数的余) |
| RAND() | 返回0~1内的随机数 |
| ROUND(X,y) | 求参数x的四舍五入的值,保留y位小数 |
通过数据库的的数,生成一个六位数的随机验证码。
SELECT lpad(ROUND(RAND()*1000000,0),6,'0'); # 左填充
SELECT RPAD(ROUND(RAND()*1000000,0),6,'0');# 右填充
日期函数
| 函数 | 功能 |
|---|---|
| CURDATE() | 返回当前日期 |
| CURTIME() | 返回当前时间 |
| NOW() | 返回当前系统日期+时间 |
| YEAR(date) | 获取指定date的年份 |
| MONTH(date) | 获取指定date的月份 |
| DAY(date) | 获取指定date的日期 |
| DATE_ADD(date, INTERVAL exp type) | 返回一个日期/时间值加上一个时间间隔expr后的时间值 |
| DATEDIFF(date1,date2) | 返回起治时间date1 和 结束时间date2之间的天数 |
# 查看当前日期
SELECT CURDATE(); # 2023-05-22
# 查看当前时间
SELECT CURTIME(); # 18:34:50
# 查看当前系统日期+时间
SELECT NOW(); # 2023-05-22 18:34:50
# 获取指定date的年份
SELECT YEAR('2023-05-22'); # 2023
# 获取指定date的月份
SELECT MONTH('2023-05-22'); # 5
# 获取指定date的日期
SELECT DAY('2023-05-22'); # 22
# 返回一个日期/时间值加上一个时间间隔expr后的时间值
SELECT DATE_ADD('2023-05-22', INTERVAL 1 DAY); # 2023-05-23
SELECT DATE_ADD('2023-05-22', INTERVAL 1 YEAR); # 2024-05-22
# 返回起治时间date1 和 结束时间date2之间的天数
SELECT DATEDIFF('2023-05-22', '2023-05-23'); # -1
# 查询所有员工的入期天数,并根据入期天数倒序排序。
SELECT name, DATEDIFF(NOW(), enter_time) AS days FROM employee ORDER BY days DESC;
流程控制函数
| 函数 | 功能 |
|---|---|
| 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,.否则返回默认值 |
| CASE [ expr] WHEN [ val1 ] THEN [res1] ... ELSE [ default ] END | 如果expr的值等于val1,返回res1,…否则返回默认值 |
开发的emp表的员工姓名和工作地址(北京/上海-一线城市 ,其他-二线城市)
SELECT name, IF((city = '北京' or city = '上海' ), '一线城市', '二线城市') AS address FROM employee;
SELECT name, CASE city WHEN '北京' THEN '一线城市' WHEN '上海' THEN '一线城市' ELSE '二线城市' END AS address FROM employee;
实战检测
查询性别男,年龄在18-20(含)之间姓名在3个字的学生信息
SELECT * FROM student WHERE gender = '男' AND age BETWEEN 18 AND 20 AND name LIKE '___';
统计员王表中,年龄小于60岁的,男性员工和女性员工的人数。
SELECT gender, COUNT(*) FROM employee WHERE age < 60 GROUP BY gender;
查询所有年龄小于等于35岁员正的姓名和年龄,并对查询结果按年龄开序播序,如果年龄相同按入眼时间降序排序。
SELECT name, age FROM employee WHERE age <= 35 ORDER BY age ASC, enter_time DESC;
查询性别为男,且年龄在20-48 岁(含)以内的前5个员工信息,对查询的结果按年龄开序播序,年龄相同按入眼时间开序播序。
SELECT * FROM employee WHERE gender = '男' AND age BETWEEN 20 AND 48 ORDER BY age ASC, enter_time ASC LIMIT 5;
统计学生分数 >= 85 优秀 >=60 及格 不及格。
SELECT name, CASE WHEN score >= 85 THEN '优秀' WHEN score >= 60 THEN '及格' ELSE '不及格' END AS score FROM student;
约束
概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。
目的:保证数据库中数据的正确、有效性和完整性。
| 关键字 | 约束 | 描述 |
|---|---|---|
| NOT NULL | 非空约束 | 限制该字段的数据不能为null |
| UNIQUE | 唯一约束 | 保证该字段的所有数据都是唯一、不重复的 |
| PRIMARY KEY | 主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 |
| DEFAULT | 默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 |
| CHECK | 检查约束(8.0.16版本之后) | 保证字段值满足某一个条件 |
| FOREIGN KEY | 外键约束 | 用来让两张表的数据之间建立连接,保证数据的一致性和完整性 |
案例展示
| 字段名 | 字段含义 | 字段类型 | 约束条件 | 约束关键字 |
|---|---|---|---|---|
| id | ID唯一标识 | 取整 | 主键,并且自动增长 | PRIMARY KEY, AUTO INCREMENT |
| 姓名 | 姓名 | varchar(10) | 不为空,并且唯一 | NOT NULL, UNIQUE |
| 年龄 | 年龄 | int | 大于0,并且小于等于120 | CHECK |
| 状态 | 状态 | char(1) | 如果没有指定该值,默认为1 | DEFAULT |
| 性别 | 性别 | char(1) | 无 | --- |
# 创建一个博客评论表
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY, -- 评论 ID,主键
content TEXT NOT NULL, -- 评论内容
username VARCHAR(100) NOT NULL UNIQUE, -- 评论者用户名(冗余字段,避免频繁查询用户表)
status ENUM('pending', 'approved', 'deleted') DEFAULT 'pending', -- 状态
gender char(1),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 评论更新时间
metadata JSON -- 扩展字段(JSON 格式,支持灵活扩展)
) comment '用户表';
外键约束
- 外键约束是作用于多张表的字段上的规则,用于限制存储在表中的数据。
- 外键约束的作用是保证两张表的数据之间建立连接,保证数据的一致性和完整性。
- 外键约束的关键字是FOREIGN KEY。
create table dept(
id int auto increment conment "ID' prinary key,
name varchar(58)not null comment'部门名称'
) connent'部们表";
INSERT INTO dept (id,name) VALUES(1,'研发部”),(2,'市场'),(3,'财务郞'),(4,'请售'),(5,'总经办');
create table emp(
id int auto_increment comment 'ID' primary key,
name varchar(50) not null comment '姓名',
age int comment '年龄',
job varchar(20) comment '职位',
salary int comment'薪资',
entrydate date comment '入职时间',
managerid int comment'直属领导ID',
dept_id int comment'部门ID
)comment'员工表";
INSERT INT0 emp (id, name, age, job, salary, entrydate, managerid, dept_id) VALUES
(1, '金庸', 66, '总裁','2000日', '2000-01-01', null, 5),
(2, '张无忌', 20, '项目经理', '1250日', '2005-12-05', 1, 1),
(3, '杨道', 33, '开发','840日', '2000-11-03', 2, 1),
(4, '韦一笑', 48, '开发', '1100日', '2002-02-05', 2, 1),
(5, '常遇春', 43, '开发', '1058日', '2004-09-07', 3, 1),
(6, '小昭', 19, '程序员鼓励师', '660日', '204-10-12', 2, 1);
外键约束的语法格式:
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (字段名) REFERENCES 主表名 (字段名);
# 创建的时候约束
CREATE TABLE table_name(
...
CONSTRAINT fk_name FOREIGN KEY (column_name) REFERENCES other_table(column_name)
) ;
# 添加外键
alter table emp add constraint fk_enp_dept_id foreign key (dept_id) references dept(id);
# 删除外键
alter table emp drop foreign key fk_enp_dept_id;
| 行为 | 说明 |
|---|---|
| NO ACTION | 当在父表中制除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许除/更新。(与RESTRICT一致) |
| RESTRICT | 当在父表中剧除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许除/更新。(与NOACTON一致) |
| CASCADE | 当在父表中剧除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也除/更新外健在子表中的记录。 |
| SET NULL | 当在父表中剧除对应记录时,首先检查该记录是否有对应外健,如果有则设置子表中该外健值为nul(这就要求该外健允许取nul)。 |
| SET DEFAULT | 父表有变更时,子表将外键列设置成一个默认的值(lnnodb不支持) |
# 外键约束的语法格式:
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (字段名) REFERENCES 主表名 (字段名) ON (update|DELETE) (NO ACTION|RESTRICT|CASCADE|SET NULL|SET DEFAULT);
多表查询
多表查询是指在一个查询中同时查询多个表的数据。多表查询可以通过连接查询、子查询、联合查询等方式实现。 多表关系:
- 一对一:一个学生只能有一个身份证,一个身份证只能属于一个学生。常用于单表拆分,例如用户信息表和用户详情扩展信息表。加入的主键要做unique约束。
- 一对多:一个部门可以有多个员工,一个员工只能属于一个部门。
- 多对多:一个学生可以选修多个课程,一个课程可以被多个学生选修。要建立一张关联表维护学生主键和课程主键之间的关系。
# 多表查询 笛卡尔积
SELECT * FROM student, course;
# 消除笛卡尔积 将关联的约束主键关联
SELECT * FROM student, course WHERE student.id = course.student_id;
多表查询分类
# 内连接查询:内连接查询是指在查询结果中只包含满足连接条件的数据。内连接查询的语法格式如下:
SELECT * FROM table1 INNER JOIN table2 ON table1.column1 = table2.column2;
# 外连接查询:外连接查询是指在查询结果中包含不满足连接条件的数据。外连接查询的语法格式如下:
SELECT * FROM table1 LEFT JOIN table2 ON table1.column1 = table2.column2; # 左连接 查询左边的表和右边表关联交集的数据 展示左表所有数据
SELECT * FROM table1 RIGHT JOIN table2 ON table1.column1 = table2.column2; # 右连接 查询左边的表和右边表关联交集的数据 展示右表所有数据
# 自查询 看成两张表 例如:员工表和员工领导都是在一张表内,查询员工的姓名和领导的姓名
SELECT a.name , b.name FROM table1 a, table2 b WHERE a.column1 = b.column2;
# 子查询:子查询是指在查询语句中嵌套另一个查询语句。子查询的语法格式如下:
SELECT * FROM table1 WHERE column1 > (SELECT column2 FROM table2);
SELECT * FROM table1 WHERE column1 (IN|NOT IN|ANY|SOME|ALL) (SELECT column2 FROM table2);
SELECT * FROM table1 where (salary,managerid) = (select salary, managerid fron table1 where nane = '张元');
select * from enp where (job,salary) in ( select job, salary fron table1 where name='张三' or nane ='李氏') ;
select e.*, d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept id = d.id ;
# 联合查询:联合查询是指将多个查询结果合并成一个结果集。联合查询的语法格式如下:
SELECT * FROM table1 UNION ALL SELECT * FROM table2;
# 联合查询去重:联合查询去重是指将多个查询结果合并成一个结果集,并去除重复的数据。联合查询去重的语法格式如下:
SELECT * FROM table1 UNION DISTINCT SELECT * FROM table2;
# 联合查询排序:联合查询排序是指将多个查询结果合并成一个结果集,并按照指定的字段进行排序。联合查询排序的语法格式如下:
SELECT * FROM table1 UNION SELECT * FROM table2 ORDER BY column1;
# 联合查询分页:联合查询分页是指将多个查询结果合并成一个结果集,并按照指定的字段进行分页。联合查询分页的语法格式如下:
SELECT * FROM table1 UNION SELECT * FROM table2 LIMIT 10, 10;
# 联合查询分组:联合查询分组是指将多个查询结果合并成一个结果集,并按照指定的字段进行分组。联合查询分组的语法格式如下:
SELECT * FROM table1 UNION SELECT * FROM table2 GROUP BY column1;
# 联合查询过滤:联合查询过滤是指将多个查询结果合并成一个结果集,并按照指定的字段进行过滤。联合查询过滤的语法格式如下:
SELECT * FROM table1 UNION SELECT * FROM table2 WHERE column1 = value;
联合查询,多用于自查询。 联合查询,多张表的字段可以必须一致,查询的字段和类型也必须一致。
多表实战
查询每一个员工的姓名,及关联的部门的名称(隐式内连接实现)
SELECT employee.name, dept.dept_name FROM employee, dept WHERE employee.dept_id = dept.id;
SELECT e.name, d.dept_name FROM employee e, dept d WHERE e.dept_id = d.id; # 使用别名后where条件必须使用表名
查询每一个员工的姓名,及关联的部门的名称(显式内连接实现)
SELECT * FROM employee INNER JOIN dept ON employee.dept_id = dept.id;
将薪资大于8000的员工的姓名和年龄大于35的查询出来
SELECT * FROM employee WHERE salary > 8000 AND age > 35;
SELECT * FROM employee WHERE salary > 8000 AND age > 35;
SELECT * FROM employee WHERE salary > 8000 UNION SELECT * FROM employee WHERE age > 35;
事务
事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。 例如:银行转账,从A账户转1000元到B账户,那么A账户就要减少1000元(前提是A有1000元),B账户就要增加1000元,这两个操作必须同时成功,要么都成功,要么都失败。
转账操作
# 查询张三账户余额
select * fron account where nane =张三;
# 张三账户余额减少1000元
update account set money =money-1000 where name ='张三';
# 李四账户余额增加1000元
update account set money =money+1000 where name ='李四';
事务操作
# 方式1
# 查看事务状态
show variables like 'autocommit'; # 1 自动提交 0 手动提交
select @@autocommit; # 1 自动提交 0 手动提交
# 关闭自动提交
set @@autocommit = 0;
# 提交事务
commit;
# 回滚事务
rollback;
# 方式2
# 查看事务状态
select @@transaction_isolation; # REPEATABLE-READ 可重复读
# 开启事务
start transaction; # 或者 begin;
# .....
# 提交事务
commit;
# 回滚事务
rollback;
方式一在修改事务状态是临时修改,服务器重启后会恢复默认状态,或在关闭数据库连接恢复。在关闭自动提交后,任何修改数据库的sql语句在执行后都需要commit提交事务修改数据库。在未提交事务和回滚事务不会影响数据库数据。
事务的特性
- 原子性:事务是不可分割的最小操作单位,事务中的所有操作要么同时成功,要么同时失败。
- 一致性:事务完成时,必须使所有的数据都保持一致状态。
- 隔离性:多个事务之间是相互隔离的,这是多个事务并发执行时,数据库为每一个事务开启的,不能被其他事务操作的数据,多个事务之间不能互相干扰,也就是说一个事务不能看到其他事务未提交的数据。
- 持久性:事务一旦提交或回滚后,数据库会把数据持久化到磁盘上。
并发事务问题
| 分类问题 | 描述 |
|---|---|
| 脏读 | 一个事务读到另外一个事务还没有提交的数据。 |
| 不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复谈。 |
| 幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影"。例如: - 事务A在查询id主键没有查到数据,事务B插入了id的数据 - 事务A插入id的数据,导致不可重复读录入数据失败 - 事务A再次查询id发现还是没有查到数据 |
事务的隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED | × | ✓ | ✓ |
| REPEATABLE READ | × | × | ✓ |
| SERIALIZABLE | × | × | × |
SELECT @@TRANSACTION_ISOLATION;
--设置当前会话事务隔离级别
SET [ SESSIONIGLOBAL] TRANSACTION ISOLATON LEVEL [ READ UNCOMMITED | READ COMMITED | REPEATABLE READ | SERALIZABLE ]