MySQL基础

173 阅读18分钟

1.MySQL概述

1.数据库相关概念

数据库(DataBase,DB): 存储数据的仓库,数据是有组织的进行存储。

数据库管理系统(DataBase Management System,DBMS): 操纵和管理数据库的大型软件。

SQL(Structured Query Language): 操纵关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准。

image.png

主流的关系型数据库管理系统:

  • Oracle
  • MySQL
  • SQL Server
  • PostgreSQL

2.MySQL数据库

下载安装配置环境变量略

安装完毕后,cmd输入 mysql --version 查看版本号,确认是否安装成功。
image.png 以管理员运行cmd:
启动MySQL:net start mysql
停止MySQL:net stop mysql
连接MySQL:mysql [-h 127.0.0.1] [-P 3306] -uroot -p
image.png

关系型数据库(RDBMS): 建立在关系模型基础上,由多张相互连接的二维表组成的数据库。

2.SQL

1.SQL的通用语法

  1. SQL语句可以单行或多行书写,以;结尾
  2. MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
  3. 注释:
    单行注释:-- 注释内容#注释内容
    多行注释:/*注释内容*/

2.SQL分类

分类全称说明
DDLData Definition Language数据定义语言,定义数据库对象(库、表、字段)
DMLData Manipulation Language数据操作语言,对表中数据进行增删改查
DQLData Query Language数据查询语言,查询表中的记录
DCLData Control Language数据控制语言,创建数据库用户、控制数据库访问权限

3.DDL

1.数据库

查询:

-- 查询所有数据库
SHOW DATABASES;
-- 查询当前数据库
SELECT DATABASE();

创建:

-- 创建数据库
CREATE DATABASE [IF NOT EXISTS] `数据库名` [DEFAULT CHARSET 字符集] [COLLATE 排序规则];

删除:

-- 删除数据库
DROP DATABASE [IF EXISTS] `数据库名`;

使用:

-- 使用数据库
USE `数据库名`;

image.png

2.表

查询:

-- 查询当前数据库所有表
SHOW TABLES;
-- 查询表结构,也可以写DESCRIBE
DESC `表名`;
-- 查询指定表的创建语句
SHOW CREATE TABLE `表名`;

创建:

-- 表的创建
CREATE TABLE `表名`(
	字段1	字段1类型[COMMENT 字段1注释],
	字段2	字段2类型[COMMENT 字段2注释],
	字段3	字段3类型[COMMENT 字段3注释],
	......
	字段4	字段4类型[COMMENT 字段4注释],
)[COMMENT 表注释];

image.png

修改:

-- 追加字段
ALTER TABLE `表名` ADD `字段名` 类型(长度) [COMMENT '注释'] [约束];

image.png

-- 修改数据类型
ALTER TABLE `表名` MODIFY `字段名` 新数据类型(长度);
-- 修改字段名和字段属性
ALTER TABLE `表名` CHANGE `旧字段名` `新字段名` 数据类型(长度) [COMMENT '注释'] [约束];

image.png

-- 删除字段
ALTER TABLE `表名` DROP `字段名`;

image.png

-- 修改表名
ALTER TABLE `表名` RENAME TO `新表名`;

image.png

-- 删除表
DROP TABLE [IF EXISTS] `表名`;
-- 删除表,并重新创建该表
TRUNCATE TABLE `表名`;

image.png

3.数据类型

MySQL中的数据类型有很多,主要分为3类:数值类型、字符串类型、日期事件类型。

数值类型:

类型大小SIGNEDUNSIGNED
TINYINT1 byte-128~1270~255
SMALLINT2 byte-32 768~32 7670~65535
MEDIUMINT3 byte-8 388 608~8 388 6070~16777215
INT/INTEGER4 byte-2 147 483 648~2 147 483 6470~4 294 967 295
BINGINT8 byte-2^63~2^63-10~2^64-1
FLOAT4 byte-3.402823466 E+38~3.402823466351 E+380 和 1.175494351 E-38~3.402823466 E+38
DOUBLE8 byte-1.7976931348623157 E+308~1.7976931348623157 E+3080 和 2.2250738585072014 E-308~1.7976931348623157 E+308
DECIMAL依赖于M(精度)和D(标度)的值依赖于M(精度)和D(标度)的值

字符类型:

类型大小说明
CHAR0~255 byte定长字符串
VARCHAR0~65 535 byte变长字符串
TINYBLOB0~255 byte不超过255个字符的二进制数据
TINYTEXT0~255 byte短文本字符串
BLOB0~65 535 byte二进制形式的长文本数据
TEXT0~65 535 byte长文本数据
MEDIUMBLOB0~16 777 215 byte二进制形式的中等长度文本数据
MEDIUMTEXT0~16 777 215 byte中等长度文本数据
LONGBLOB0~4 294 967 295 byte二进制形式的极大文本数据
LONGTEXT0~4 294 967 295 byte极长文本数据

注意:

  • char(7)int(7) 类似,7指定存储空间,是固定的
  • varchar(7) 7表示保存的最大字符数,会根据实际情况来开辟空间
  • 故而,char的性能比varchar好一些,但varchar会更省空间
  • int(7) 则是表名显示宽度,不会影响存储

日期类型

类型大小范围格式说明
DATE31000-01-01 至 9999-12-31YYYY-MM-DD日期值
TIME3-838:59:59 至 838:59:59HH:MM:SS时间值或持续时间
YEAR11901 至 2155YYYY年份值
DATETIME81000-01-01 00:00:00 至 9999-12-31 23:29:29YYYY-MM-DD HH:MM:SS混合日期和时间值
TIMESTAMP41970-01-01 00:00:01 至 2038-01-19 03:14:07YYYY-MM-DD HH:MM:SS混合日期和时间值,时间戳

员工表:
image.png
sql语句:
image.png

4.小结

指令说明
SHOW DATABASES;查询所有数据库
SELECT DATABASE();查询当前数据库
CREATE DATABASE 数据库名;创建数据库
DROP DATABASE 数据库名;删除数据库
USE 数据库名;使用数据库
SHOW TABLES;查询当前数据库所有表
DESC 表名;询表结构,也可以写DESCRIBE
SHOW CREATE TABLE 表名;查询指定表的创建语句
CREATE TABLE 表名(...)表的创建
ALTER TABLE 表名 ADD 字段名 类型(长度);追加字段
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);修改数据类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 数据类型(长度);修改字段名和字段属性
ALTER TABLE 表名 DROP 字段名;删除字段
ALTER TABLE 表名 RENAME TO 新表名;修改表名
DROP TABLE 表名;删除表
TRUNCATE TABLE 表名;删除表,并重新创建该表

4.DML

1.添加数据(INSERT)

-- 给指定字段添加数据
INSERT INTO 表名(字段名1,字段名2,...) VALUES(值1,值2,...);
-- 给全部字段添加数据
INSERT INTO 表名 VALUES(值1,值2,...);
-- 批量添加数据
INSERT INTO 表名(字段名1,字段名2,...) VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...);
INSERT INTO 表名 VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...);

注意:

  • 插入数据时,指定的字段顺序需要与值得顺序一一对应
  • 字符串和日期类型数据应该包含在引号中
  • 插入的数据大小,应该在字段的规定范围内

image.png

INSERT INTO employee(id,workno,`name`,gender,age,idcard,entrydate) 
VALUES(1,'1','张三','男','17','510104200503077278','2022-01-01');

INSERT INTO employee 
VALUES(2,'2','李四','男','17','510104200503079679','2022-01-02');

INSERT INTO employee(id,workno,`name`,gender,age,idcard,entrydate) 
VALUES(3,'3','王五','男','17','510104200503076195','2022-01-03'),(4,'4','赵六','男','17','510104200503072813','2022-01-04');

INSERT INTO employee 
VALUES(4,'4','杰克','男','17','510104200503070893','2022-01-05'),(5,'5','肉丝','女','20','110101200203071583','2022-01-05');

image.png

2.修改数据(UPDATE)

-- 修改数据
UPDATE 表名 SET 字段名1=1,字段名2=2,...[WHERE 条件];

注意: 如果不添加条件,会修改整张表所有数据。

UPDATE employee SET `name` = 'Rose' WHERE id = 5;
UPDATE employee SET `name` = 'Jack',entrydate = '2020-01-12' WHERE id = 4;

image.png

3.删除数据(DELETE)

-- 删除数据
DELETE FROM 表名 [WHERE 条件];

注意:

  • DELETE 语句不加上条件,就会删除整张表的所有数据
  • DELETE 语句不能删除某一个字段的值(可以使用UPDATE)
DELETE FROM employee WHERE id = 5;

image.png

4.小结

指令说明
INSERT INTO 表名(字段名1,字段名2,...) VALUES(值1,值2,...);添加数据
UPDATE 表名 SET 字段名1=值1,字段名2=值2,...[WHERE 条件];修改数据
DELETE FROM 表名 [WHERE 条件];删除数据

5.DQL

1.基础查询+条件查询

查询多个字段:

-- 查询多个字段
SELECT 字段1,字段2,字段3 ... FROM 表名;
SELECT * FROM 表名;

-- 设置别名
SELECT 字段1 [AS 别名1],字段2 [别名2] ... FROM 表名;

-- 去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;

给表格添加数据:
image.png image.png

条件语句中的运算符:

比较运算符说明
> >= < <= =
<> 或 !=不等于
BETWEEN ... AND ...在某个范围之内(包含边界值)
IN(...)在 in 之后的列表中的值,多选一
LIKE 占位符模糊查询(_ 匹配单个字符 % 匹配任意个字符)
IS NULL是NULL

image.png

逻辑算符说明
AND 或 &&
OR 或
NOT 或 !

image.png

2.聚合查询

聚合查询:

常见聚合函数:

函数说明
COUNT统计数量
MAX最大值
MIN最小值
AVG平均值
SUM求和
-- 聚合查询
SELECT 聚合函数(字段列表) FROM 表名;

注意: 使用聚合函数的时候,NULL值不参与计算。

image.png

3.分组查询

-- 分组查询
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];

where和having的区别:

  • 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;having是分组之后对结果进行过滤
  • 判断条件不同:where不能对聚合函数进行判断,而having可以

image.png

image.png

注意:

  • 执行顺序:where > having
  • 分组之后,查询的字段一般为聚合函数或分组字段,查询其他字段毫无意义

4.排序查询

-- 排序查询
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;

排序方式:

  • ASC 升序排序(默认)
  • DESC 降序排序

image.png

5.分页查询

-- 分页查询
SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;

注意:

  • 起始索引从0开始,起始索引 = (查询页码-1)* 每页显示记录数
  • 分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是limit
  • 如果查询的是第一页数据,起始索引可以省略,直接简写成limit 查询记录数

image.png

image.png

6.执行顺序

  1. from
  2. where
  3. group by
  4. having
  5. select
  6. order by
  7. limit

7.小结

SELECT 字段列表
FROM 表名列表
WHERE 条件列表
GROUP BY 分组字段列表
HAVING	分组后条件列表
ORDER BY 排序字段列表
LIMIT	分页参数

6.DCL

1.用户创建与删除

-- 查询用户
USE mysql;
SELECT * FROM user;

-- 创建用户
CREATE USER '用户名'@'主机号' IDENTIFIED BY '密码';

-- 修改用户密码
ALTER USER '用户名'@'主机号' IDENTIFIED WITH mysql_native_password BY '新密码';

-- 删除用户
DROP USER '用户名'@'主机号';

image.png

2.权限控制

MySQL中常用的权限:

权限说明
ALL,ALL PRIVILEGES所有权限
SELECT查询数据
INSERT插入数据
UPDATE修改数据
DELETE删除数据
ALTER修改表
DROP删除数据库/表/视图
CREATE创建数据库/表
-- 查询权限
SHOW GRANTS FOR '用户名'@'主机号';

-- 授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机号';

-- 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机号';

新建用户的权限:只有登录连接的权限
image.png

权限控制
image.png

注意:

  • 多个权限之间,用 , 分隔
  • 授权时,数据库名和表名可以使用 * 代表所有

3.小结

指令说明
CREATE USER '用户名'@'主机号' IDENTIFIED BY '密码';创建用户
SELECT * FROM user;查询所有用户
ALTER USER '用户名'@'主机号' IDENTIFIED WITH mysql_native_password BY '新密码';修改用户密码
DROP USER '用户名'@'主机号';删除用户
SHOW GRANTS FOR '用户名'@'主机号';查询权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机号';授予权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机号';撤销权限

3.函数

1.字符串函数

函数说明
CONCAT(str1,str2,...)字符串拼接,将S1、S2、...拼接成一个字符串
LOWER(str)将字符串str全部转小写
UPPER(str)将字符串str全部转大写
LPAD(str,len,padstr)左填充,用字符串padstr对str的左边进行填充,达到n个字符串长度
RPAD(str,len,padstr)右填充,用字符串padstr对str的右边进行填充,达到n个字符串长度
TRIM(str)去掉字符串头部和尾部的空格
SUBSTRING(str,start,len)返回从字符串str从start位置起的len个长度的字符串

image.png

image.png

2.数值函数

函数说明
CEIL(X)向上取整
FLOOR(X)向下取整
MOD(N,M)返回N/M的模
RAND()返回0~1内的随机数
ROUND(X,Y)返回X四舍五入的值,保留Y位小数

image.png

3.日期函数

函数说明
CURDATE()返回当前日期
CURTIME()返回当前时间
NOW()返回当前日期和时间
YEAR(date)获取指定date的年份
MONTH(date)获取指定date的月份
DAY(date)获取指定date的日期
DATE_ADD(date,INTERVAL expr unit)返回一个日期/时间加上一个时间间隔expr后的时间值
DATEDIFF(date1,date2)返回起始时间date1 和结束时间 date2之间的天数

image.png

image.png

4.流程函数

函数说明
IF(expr1,expr2,expr3)如果value为true,返回expr2,否则返回expr3
IFNULL(expr1,expr2)如果expr1不为空,返回expr1,否则返回expr2
CASE case_value
WHEN when_value THEN
statement_list1
ELSE
statement_list2
END CASE;
如果case_value值等于when_value,返回statement_list1
否则返回statement_list2
CASE WHEN when_value THEN
statement_list1
ELSE
statement_list2
END CASE;
如果 when_value 为true,返回statement_list1,否则返回statement_list2

image.png

image.png

5.小结

类型函数
字符串函数COUNT、LOWER、UPPER、LPAD、RPAD、TRIM、SUBSTRING
数值函数CEIL、FLOOR、MOD、RAND、ROUND
日期函数CURDATE、CURTIM、NOW、YEAR、MONTH、DAY、DATE_ADD、DATEDIFF
流程函数IF、IFNULL、CASE case_value WHEN、CASE WHEN

4.约束

1.概述

约束: 作用于表中字段上的规则,用于限制存储在表中的数据。

目的: 保证数据库中数据的正确、有效性和完整性。

约束说明关键字
非空约束限制字段的数据不能为nullNOT NULL
唯一约束保证该字段的所有数据都是唯一的UNIQUE
主键约束一行数据的唯一标识,非空且唯一PRIMARY KEY
默认约束没有指定该字段的值,就采用默认值DEFAULT
检索约束保证字段值满足某一条件CHECK
外键约束在两张表之间建立连接,保证数据的一致性和完整性FOREIGN KEY

注意: 约束是作用于字段上的,可以再创建/修改表的时候添加约束。

2.约束演示

CREATE TABLE user(
	id INT PRIMARY KEY auto_increment COMMENT '主键',
	`name` VARCHAR(20) NOT NULL UNIQUE COMMENT '姓名',
	age INT CHECK (age > 0 && age <= 123) COMMENT '年龄',
	`status` CHAR(1) DEFAULT('1') COMMENT '状态',
	gender CHAR(1) COMMENT '性别'
)COMMENT '用户表';

INSERT INTO user(name,age,status,gender) 
VALUES('张三',17,1,'男'),('李四',24,2,'男'),('王五',35,3,'男'),('赵六',6,0,'男'),('翠花',18,1,'女'),('淑芬',25,2,'女');

INSERT INTO user(id,name,age,gender) VALUES(7,'Jack',17,'男'); # status使用默认值1

3.外键约束

1.相关指令

外键: 让两张表之间建立连接,从而保证数据的一致性和完整性。

新建两张表并插入数据:

CREATE TABLE dept(
	id INT auto_increment COMMENT '编号' PRIMARY KEY,
	name VARCHAR(30) NOT NULL COMMENT '部门名称'
) COMMENT '部门表';

INSERT INTO dept VALUES (1,'研发部'),(2,'市场部'),(3,'财务部'),(4,'销售部'),(5,'总经办');

CREATE TABLE emp(
	id INT auto_increment COMMENT 'ID' PRIMARY KEY,
	name VARCHAR(30) 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 INTO emp(id,name,age,job,salary,entrydate,managerid,dept_id) VALUES
(1,'昊天',999,'总裁',999999,'2000-01-01',NULL,5),
(2,'夫子',102,'副总裁',888888,'2002-01-01',NULL,5),
(3,'柯浩然',27,'全栈开发',200000,'2012-01-01',2,1),
(4,'陈某',27,'项目经理',888888,'2005-01-01',1,2),
(5,'宁缺',19,'后端开发',888888,'2018-01-01',2,1);

image.png

添加外键:

-- 添加外键
CREATE TABLE 表名(
	字段名 数据类型,
	...
	[CONSTRAINT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名);
);

-- 添加外键
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名);

-- 删除外键
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept(id);

image.png

ALTER TABLE emp DROP FOREIGN KEY fk_emp_dept_id;

2.外键删除更新行为

行为说明
NOT ACTION当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(同RESTRICT)
RESTRICT当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(同NOT ACTION)
CASCADE当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录
SET NULL当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置字表中该外键值为null(需要允许该外键取null)
SET DEFAULT当父表有变更时,子表将外键列设置成一个默认的值(InnoDB不支持)
-- 设置外键行为
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (外键字段) REFERENCES 主表名(主表字段名) ON UPDATE 行为 ON DELETE 行为;
-- 添加外键
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept(id) ON UPDATE CASCADE ON DELETE CASCADE;

5.多表查询

1.多表关系

表之间的关系:

  • 一对多(多对一)
    如:image.png

  • 多对多
    如学生和课程的关系
    实现:建立第三张中间表,中间表至少要包含两个外键,分别关联两方主键

  • 一对一
    多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率
    实现:在任意一方加入外键,关联另一方的主键,并设置外键为唯一的(UNIQUE)

2.多表查询

从多张表中查询数据。

注意: 在多表查询时,需要消除无效的笛卡尔积。

  • 笛卡尔积:两个集合A和集合B的所有组合情况image.png

多表查询分类:

  • 连接查询:
    内连接:查询A、B交集部分数据
    外连接:左外连接(查询左表所有数据)、右外连接(查询右表所有数据)
    自连接:当前表与自身的连接查询,自连接必须使用表别名
  • 子查询

1.内连接

内连接查询的是两张表的交集部分:
image.png

-- 隐式内连接
SELECT 字段列表 FROM1,表2 WHERE 条件...;

-- 显式内连接
SELECT 字段列表 FROM1 [INNER] JOIN2 ON 连接条件...;

image.png

2.外连接

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/649159db50af4b2795fd869ae8be2180~tplv-k3u1fbpfcp-watermark.image?)
-- 左外连接
-- 查询表1的所有数据包含两表的交集部分
SELECT 字段列表 FROM1 LEFT [OUTER] JOIN2 ON 条件...;

-- 右外连接
-- 查询表2的所有数据包含两表的交集部分
SELECT 字段列表 FROM1 RIGHT [OUTER] JOIN2 ON 条件...;

image.png

3.自连接

-- 自连接
SELECT 字段列表 FROM1 JOIN1 别名1 ON 条件...;

自连接查询:分为内连接查询和外连接查询

image.png

4.联合查询

把多次查询的结果合并起来,形成一个新的查询结果集。

SELECT 字段列表 FROM 表A...
UNION[ALL]
SELECT 字段列表 FROM 表B...;

image.png

注意:

  • union all 会将全部的数据直接合并在一起
  • union 会对合并后的数据去重

5.子查询

即SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。

SELECT 字段列表 FROM1 
WHERE 字段1 = (SELECT 字段1 FROM2);

子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个

子查询的分类(根据查询结果):

  • 标量子查询(子查询的结果为单个值)image.png
  • 列子查询(子查询结果为一列)
    常用操作符:IN、NOT IN、 ANY、SOME、ALLimage.png
  • 行子查询(子查询结果为一行)image.png
  • 表子查询(子查询结果为多行多列)
    常用的操作符:INimage.png

子查询的分类(根据查询位置)

  • WHERE之后
  • FROM之后
  • SELECT之后

3.小结

多表关系:

关系说明
一对多在多的一方设置外键,关联的一的一方的主键
多对多建立中间表,中间表包含两个外键,关联两张表的主键
一对一用于表结构拆分,在其中任何一方设置外键(UNIQUE),关联另一方的主键

多表查询:

关系说明
内连接隐式: SELECT...FROM 表A,表B WHERE 条件...
显式: SELECT...FROM 表A INNER JOIN 表B ON 条件...
外连接左外:SELECT...FROM 表A LEFT JOIN 表B ON 条件...
右外:SELECT...FROM 表A RIGHT JOIN 表B ON 条件...
自连接SELECT 字段列表 FROM 表1 JOIN 表1 别名1 ON 条件...;
联合查询SELECT 字段列表 FROM 表A...UNION[ALL] SELECT 字段列表 FROM 表B...;
子查询标量子查询、列子查询、行子查询、表子查询

6.事务

1.演示

事务: 一组操作的集合,是一个不可分割的工作单位(最小工作单位),事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,这些操作要么同时成功,要么同时失败。

-- 开启事务
BEGIN;
-- 或者
START TRANSACTION;


-- 回滚
ROLLBACK;

-- 提交
COMMIT;

创建数据库:
image.png

关闭自动提交:
image.png


image.png

2.四大特性

原子性(Atomicity): 事务是不可分割的最小操作单元,要么全部成功,要么全部失败。

一致性(Consistency): 事务完成时,必须使所有的数据都保持一致状态。

隔离性(Isolation): 数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。

持久性(Durability): 事务一旦提交或回滚,它对数据库中的数据的改变是永久的。

3.并发问题

1.脏读

脏读(Dirty read): 一个事务读取到了另一个事务 未提交 的数据。

图解:以下为自动提交事务关闭情况

事务2修改了age(age=19),但并未提交,这时候事务1却读取了此数据(age=19),而事务2却回滚取消了此数据修改(age=18)。 这时候数据库中age的age是18,但是事务1却读到了age是19,故而产生了脏读。

2.不可重复度

不可重复度(Non-repeatable read): 一个事务中前后执行两次相同的查询操作,由于第二次读取到了其他事务 已提交 的数据,得到了不同的查询结果。

事务1第一次度到的id为1的age为18,之后由于事务2对于数据的修改(已提交),事务1再次读取age,确实19,两次读取的结果不一致。

3.幻读

幻读(Phantom)与不可重复度的区别: 由于 插入数据 而导致两次查询结果不一致叫幻读,由于 删改 数据而导致两次查询结果不一致叫不可重复读。

4.隔离级别

读未提交(READ UNCOMMITTED): 可以读取到事务未提交的数据,最低的事务隔离级别。

读已提交(READ COMMITTED): 只能读已提交的数据,解决了脏读。

可重复读(REPEATABLE READ): 一个事务开始读取数据后, 其他事务不能修改数据(update/delete),解决的可重复读、脏读。

串行化(SERIALIZABLE): 事务一个一个地排队执行,不能进行并发操作,可以避免所有并发问题。但是效率低下,很消耗数据库性能。

隔离级别脏读不可重复读幻读
读未提交
读已提交
可重复读
串行化

事务隔离级别预告,并发度越低。

注意: InnoDB在可重复读级别已经解决了幻读的问题,完全不需要使用到串行化。InnoDB的默认级别是可重复读。

-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;

-- 设置事务隔离级别
-- SESSION 当前客户端;GLOBAL 所有客户端
SELECT [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMIT | REPEATABLE READ | SERIALIZABLE}