MySQL 基础学习笔记
本文系统梳理MySQL基础知识点,涵盖SQL语言分类(DDL、DML、DQL、DCL、TCL)、数据类型(数值、字符串、日期时间)、表结构操作(创建、修改、删除)、数据增删改查及约束、函数、多表查询、子查询与事务控制。重点强调:使用DECIMAL存储金额、TIMESTAMP自动更新时间、UPDATE需加WHERE避免全表误改,以及事务的ACID特性与控制语句。内容全面,适合作为复习与进阶参考。
1. SQL 基础
1.1 什么是 SQL
结构化查询语言(SQL, Structured Query Language)是一种用于在关系数据库中存储和处理信息的编程语言。关系数据库以表格形式存储信息:行表示记录,列表示字段(数据属性),表与表之间通过数据值建立关系。使用 SQL 可以完成数据的存储、更新、删除、检索,以及数据库的维护与性能优化。
1.2 SQL 命令分类
| 分类 | 全称 | 说明 | 常用命令 |
|---|---|---|---|
| DDL | Data Definition Language | 数据定义语言,用来定义数据库对象(数据库、表、字段) | CREATE、DROP、ALTER、TRUNCATE |
| DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改 | INSERT、DELETE、UPDATE |
| DQL | Data Query Language | 数据查询语言,用来查询数据库中表的记录 | SELECT |
| DCL | Data Control Language | 数据控制语言,用来创建数据库用户、控制数据库的访问权限 | GRANT、REVOKE |
| TCL | Transaction Control Language | 事务控制语言,用来控制事务的提交与回滚 | COMMIT、ROLLBACK、SAVEPOINT |
记忆口诀:定(DDL)义结构、操(DML)作数据、查(DQL)询记录、控(DCL)制权限、事(TCL)务控制。
2. MySQL 数据类型
2.1 数值类型
| 类型 | 大小 | 有符号(SIGNED)范围 | 无符号(UNSIGNED)范围 | 描述 |
|---|---|---|---|---|
| TINYINT | 1 byte | (-128, 127) | (0, 255) | 小整数值 |
| SMALLINT | 2 bytes | (-32768, 32767) | (0, 65535) | 大整数值 |
| MEDIUMINT | 3 bytes | (-8388608, 8388607) | (0, 16777215) | 大整数值 |
| INT 或 INTEGER | 4 bytes | (-2147483648, 2147483647) | (0, 4294967295) | 大整数值 |
| BIGINT | 8 bytes | (-2^63, 2^63-1) | (0, 2^64-1) | 极大整数值 |
| FLOAT | 4 bytes | (-3.402823466 E+38, 3.402823466 E+38) | 0 和 (1.175494351 E-38, 3.402823466 E+38) | 单精度浮点数值 |
| DOUBLE | 8 bytes | (-1.7976931348623157 E+308, 1.7976931348623157 E+308) | 0 和 (2.2250738585072014 E-308, 1.7976931348623157 E+308) | 双精度浮点数值 |
| DECIMAL | 依赖于 M(精度) 和 D(标度) 的值 | 依赖于 M(精度) 和 D(标度) 的值 | 依赖于 M(精度) 和 D(标度) 的值 | 小数值(精确定点数) |
要点补充:
- 整数类型可加
UNSIGNED修饰,表示无符号非负数。 FLOAT/DOUBLE是近似值,存在精度损失;金额等要求精确的场景用DECIMAL(M,D),M 是总位数(精度),D 是小数位数(标度)。INT(11)中的数字只影响显示宽度,不限制取值范围。
2.2 字符串类型
| 类型 | 大小 | 描述 |
|---|---|---|
| CHAR | 0-255 bytes | 定长字符串 |
| VARCHAR | 0-65535 bytes | 变长字符串 |
| TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制数据 |
| TINYTEXT | 0-255 bytes | 短文本字符串 |
| BLOB | 0-65535 bytes | 二进制形式的长文本数据 |
| TEXT | 0-65535 bytes | 长文本数据 |
| MEDIUMBLOB | 0-16777215 bytes | 二进制形式的中等长度文本数据 |
| MEDIUMTEXT | 0-16777215 bytes | 中等长度文本数据 |
| LONGBLOB | 0-4294967295 bytes | 二进制形式的极大文本数据 |
| LONGTEXT | 0-4294967295 bytes | 极大文本数据 |
要点补充:
CHAR(n)定长:不足 n 补空格,节省计算、浪费空间;VARCHAR(n)变长:按实际长度存储并额外记录长度,节省空间。- 经验法则:长度固定或很短(如性别、MD5)用
CHAR,长度可变用VARCHAR;BLOB 存二进制(图片、文件),TEXT 存大段文本。 - VARCHAR 的 n 按字符计,CHAR 也按字符计,实际占用字节数与字符集有关(utf8mb4 一个字符最多 4 字节)。
2.3 日期时间类型
| 类型 | 大小 | 范围 | 格式 | 描述 |
|---|---|---|---|---|
| DATE | 3 | 1000-01-01 至 9999-12-31 | YYYY-MM-DD | 日期值 |
| TIME | 3 | -838:59:59 至 838:59:59 | HH:MM:SS | 时间值或持续时间 |
| YEAR | 1 | 1901 至 2155 | YYYY | 年份值 |
| DATETIME | 8 | 1000-01-01 00:00:00 至 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
| TIMESTAMP | 4 | 1970-01-01 00:00:01 至 2038-01-19 03:14:07 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值,时间戳 |
要点补充:
DATETIME与TIMESTAMP都能存"日期+时间",区别:TIMESTAMP 范围小(存在 2038 问题)、占 4 字节、与时区相关,且列可自动维护(插入/更新时自动填充当前时间);DATETIME 与时区无关。- 记录"创建时间、更新时间"这类审计字段,常用
TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。
3. 数据定义语言 DDL
3.1 数据库操作
| 操作 | 语法 |
|---|---|
| 查询所有数据库 | SHOW DATABASES; |
| 查询当前数据库 | SELECT DATABASE(); |
| 创建数据库 | CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则]; |
| 删除数据库 | DROP DATABASE [IF EXISTS] 数据库名; |
| 使用数据库 | USE 数据库名; |
3.2 表操作 ------ 查询
| 操作 | 语法 |
|---|---|
| 查询当前数据库所有表 | SHOW TABLES; |
| 查询表结构 | DESC 表名; |
| 查询指定表的建表语句 | SHOW CREATE TABLE 表名; |
3.3 表操作 ------ 创建
sql
CREATE TABLE 表名(
字段1 字段1类型 [COMMENT 字段1注释],
字段2 字段2类型 [COMMENT 字段2注释],
字段3 字段3类型 [COMMENT 字段3注释],
......
字段n 字段n类型 [COMMENT 字段n注释]
)[COMMENT 表注释];
注意:[...] 为可选参数,最后一个字段后面没有逗号。
3.4 表操作 ------ 修改
| 操作 | 语法 |
|---|---|
| 添加字段 | ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束]; |
| 修改数据类型 | ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度); |
| 修改字段名和字段类型 | ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束]; |
| 删除字段 | ALTER TABLE 表名 DROP 字段名; |
| 修改表名 | ALTER TABLE 表名 RENAME TO 新表名; |
记忆:CHANGE 改名又改型(必须写新类型),MODIFY 只改类型不改名。
3.5 表操作 ------ 删除
| 操作 | 语法 |
|---|---|
| 删除表 | DROP TABLE [IF EXISTS] 表名; |
| 删除指定表,并重新创建该表(清空数据) | TRUNCATE TABLE 表名; |
注意:在删除表时,表中的全部数据也会被删除。
4. 数据操作语言 DML ------ 添加数据
| 场景 | 语法 |
|---|---|
| 给指定字段添加数据 | 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, ...); |
注意:
- 字符串和日期值要用单引号包裹,数值可以直接写。
- 未指定
AUTO_INCREMENT主键列时可省略不写,由数据库自动递增。
5. DML ------ 修改与删除数据
5.1 修改数据(UPDATE)
sql
UPDATE 表名 SET 字段名1=值1, 字段名2=值2, ... [WHERE 条件];
示例:
sql
UPDATE employee SET age = 30 WHERE id = 1; -- 修改指定记录
UPDATE employee SET salary = salary * 1.1; -- 不带 WHERE,修改全表所有记录
⚠️ 不写 WHERE 条件会更新全表数据,这是生产事故的高发点,务必养成先写 WHERE 再写 SET 的习惯。
5.2 删除数据(DELETE)
sql
DELETE FROM 表名 [WHERE 条件];
示例:
sql
DELETE FROM employee WHERE name = '张三'; -- 删除指定记录
DELETE FROM employee; -- 删除表中全部数据(表结构保留)
5.3 DELETE / TRUNCATE / DROP 对比(高频面试题)
| 对比项 | DELETE | TRUNCATE | DROP |
|---|---|---|---|
| 语言类别 | DML | DDL | DDL |
| 删除范围 | 可按 WHERE 删部分行 | 清空整表数据 | 整张表(结构+数据) |
| 表结构是否保留 | 保留 | 保留 | 不保留 |
| 能否回滚(事务中) | 可以 | 不可以 | 不可以 |
| 速度 | 慢(逐行删除并记录日志) | 快 | 快 |
| 自增主键计数器 | 不清零 | 清零重新计数 | 随表一起删除 |
6. 数据查询语言 DQL(重点)
6.1 基本查询
sql
SELECT 字段1, 字段2, ... FROM 表名;
SELECT * FROM 表名; -- 查询所有字段
SELECT DISTINCT 字段 FROM 表名; -- 去重:消除结果集中完全相同的行
SELECT 字段1 AS 别名, 字段2 别名 FROM 表名; -- 列别名,AS 可省略
SELECT CONCAT(姓, 名) AS 姓名 FROM 表名; -- 拼接列后作为一列输出
6.2 条件查询(WHERE)
sql
SELECT 字段... FROM 表名 WHERE 条件;
比较运算符:
| 运算符 | 含义 |
|---|---|
= |
等于 |
> / >= |
大于 / 大于等于 |
< / <= |
小于 / 小于等于 |
<> 或 != |
不等于 |
BETWEEN...AND... |
在某个范围内(闭区间,含两端) |
IN(...) |
匹配括号中任意一个值 |
LIKE |
模糊匹配 |
IS NULL / IS NOT NULL |
是否为空 / 不为空 |
逻辑运算符 :AND(并且)、OR(或者)、NOT(非)。
LIKE 通配符:
| 通配符 | 含义 |
|---|---|
% |
任意多个字符,包含 0 个字符 |
_ |
任意单个字符 |
示例:
sql
SELECT * FROM employee WHERE name LIKE '张%'; -- 姓张的所有人
SELECT * FROM employee WHERE name LIKE '张_'; -- 姓张且名字为两个字
SELECT * FROM employee WHERE age IN (20, 30, 40); -- 年龄是 20/30/40
SELECT * FROM employee WHERE age BETWEEN 20 AND 30;
SELECT * FROM employee WHERE score IS NULL; -- 注意:判空必须用 IS NULL
⚠️ NULL 的特殊性:任何值与 NULL 做比较结果都是 NULL(未知)。score = NULL 永远查不到数据,必须写 score IS NULL;!= 也查不出 NULL 行。
6.3 排序查询(ORDER BY)
sql
SELECT 字段... FROM 表名 ORDER BY 字段1 [ASC|DESC], 字段2 [ASC|DESC];
ASC升序(默认)、DESC降序。- 多个排序条件:前一根列相同时,才按下一列排序。
- 若有 WHERE,先过滤、后排序。
sql
SELECT * FROM employee ORDER BY age ASC, salary DESC;
6.4 聚合函数
将一列数据作为一个整体,进行纵向计算。
| 函数 | 功能 |
|---|---|
COUNT(字段) |
统计数量(常用 COUNT(*) 统计行数) |
MAX(字段) |
最大值 |
MIN(字段) |
最小值 |
AVG(字段) |
平均值 |
SUM(字段) |
求和 |
sql
SELECT COUNT(*) FROM employee WHERE age <= 35;
SELECT AVG(salary), MAX(salary) FROM employee;
⚠️ 聚合函数计算时忽略 NULL 值 :COUNT(score) 统计的是 score 非 NULL 的行数,与 COUNT(*) 可能不同;求平均分若想 NULL 按 0 算,需先 IFNULL(score, 0)。
6.5 分组查询(GROUP BY / HAVING)
sql
SELECT 分组字段, 聚合函数(字段) FROM 表名 [WHERE 条件]
GROUP BY 分组字段 [HAVING 分组后条件] [ORDER BY 字段];
示例:
sql
-- 每个部门的人数
SELECT dept, COUNT(*) FROM employee GROUP BY dept;
-- 年龄 35 岁及以下的人,根据性别分组,统计男/女年龄平均值
SELECT gender, AVG(age) FROM employee WHERE age <= 35 GROUP BY gender;
-- 查询人数大于 2 的部门
SELECT dept, COUNT(*) FROM employee GROUP BY dept HAVING COUNT(*) > 2;
WHERE 与 HAVING 的区别(必考):
| 对比 | WHERE | HAVING |
|---|---|---|
| 执行时机 | 分组前过滤 | 分组后过滤 |
| 能否用聚合函数 | 不能 | 能 |
执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。分组后能 SELECT 的只有分组字段和聚合函数,其余列的值无意义。
6.6 分页查询(LIMIT)
sql
SELECT 字段... FROM 表名 LIMIT 起始索引, 记录条数;
- 起始索引从 0 开始;第一页:
LIMIT 0, 10,第二页:LIMIT 10, 10。 - 公式:起始索引 = (页码 - 1) × 每页条数。
- 只写
LIMIT 10表示从第 0 条开始取 10 条。
7. 约束(Constraint)
约束是作用于数据表列上的规则,保证数据的完整性、正确性、有效性。
| 约束 | 关键字 | 作用 |
|---|---|---|
| 非空约束 | NOT NULL | 字段值不能为 NULL |
| 唯一约束 | UNIQUE | 字段值不能重复(可为 NULL,且只允许一个 NULL) |
| 主键约束 | PRIMARY KEY | 唯一 + 非空,一行数据的唯一标识,一张表只能有一个 |
| 外键约束 | FOREIGN KEY | 保证两张表之间数据的关联有效性 |
| 默认约束 | DEFAULT | 插入数据未指定该列时,自动使用默认值 |
| 自动增长 | AUTO_INCREMENT | 整数列自动按 1 递增,常配合主键使用 |
7.1 建表时定义
sql
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10) NOT NULL UNIQUE,
age INT,
gender VARCHAR(1) DEFAULT '女',
class_id INT,
CONSTRAINT fk_stu_cls FOREIGN KEY (class_id) REFERENCES class(id)
);
7.2 建表后添加 / 删除
sql
-- 添加非空 / 唯一 / 默认
ALTER TABLE student MODIFY name VARCHAR(10) NOT NULL;
ALTER TABLE student MODIFY name VARCHAR(10) UNIQUE;
ALTER TABLE student MODIFY gender VARCHAR(1) DEFAULT '男';
-- 添加 / 删除主键
ALTER TABLE student MODIFY id INT PRIMARY KEY;
ALTER TABLE student DROP PRIMARY KEY;
-- 添加 / 删除外键
ALTER TABLE student ADD CONSTRAINT fk_stu_cls FOREIGN KEY (class_id) REFERENCES class(id);
ALTER TABLE student DROP FOREIGN KEY fk_stu_cls;
7.3 外键要点
- 语法:
FOREIGN KEY (本表字段) REFERENCES 主表(主表字段)。 - 被引用列必须是主键或唯一列;两列类型要兼容。
- 有外键引用时,删除主表被引用的行、或修改被引用的主键值会报错;插入从表时外键值必须在主表中存在(或为 NULL)。
- 一对一、一对多:外键放在"多"的一方;多对多:需要第三张中间表,各放一个外键。
8. 多表查询
8.1 笛卡尔积与隐式内连接
两张表无条件连接会产生笛卡尔积(行数相乘),用 WHERE 过滤掉无效结果就是隐式内连接:
sql
-- 查询员工姓名及其部门名称
SELECT e.name, d.dept_name
FROM employee e, dept d
WHERE e.dept_id = d.id;
8.2 显式内连接(INNER JOIN)
sql
SELECT e.name, d.dept_name
FROM employee e
INNER JOIN dept d ON e.dept_id = d.id; -- INNER 可省略,写 JOIN 即可
内连接只返回两表能匹配上的行;无匹配员工的部门、无所属部门的员工都不会出现。
8.3 外连接(OUTER JOIN)
sql
-- 左外连接:左表所有行都保留,右表匹配不上则为 NULL
SELECT e.name, d.dept_name
FROM employee e
LEFT JOIN dept d ON e.dept_id = d.id;
-- 右外连接:右表所有行都保留(与左外对称,实际开发中常用左外+调换表顺序代替)
SELECT e.name, d.dept_name
FROM employee e
RIGHT JOIN dept d ON e.dept_id = d.id;
典型用法:查"所有员工及其部门(包括没有部门的员工)"用左外连接;查"所有部门及其员工人数(包括没有员工的部门)"用右外连接或以 dept 为左表。
8.4 自连接
一张表和自己连接,用于表内存在层级关系的数据(如员工与领导):
sql
-- 查询每个员工及其领导的姓名
SELECT e.name AS 员工, m.name AS 领导
FROM employee e
LEFT JOIN employee m ON e.managerid = m.id; -- 外连接才能保留没有领导的员工
8.5 UNION 合并结果集
sql
SELECT ... UNION SELECT ...; -- 合并并去重
SELECT ... UNION ALL SELECT ...; -- 合并不去重,性能更好
9. 子查询(嵌套查询)
SQL 语句中嵌套 SELECT 语句,称为子查询,外层为主查询。子查询按返回结果分为 4 类:
9.1 标量子查询(返回单个值)
sql
-- 查询"销售部"的所有员工信息
SELECT * FROM employee
WHERE dept_id = (SELECT id FROM dept WHERE dept_name = '销售部');
可用于 WHERE、SELECT 等任何需要值的位置。
9.2 列子查询(返回一列多行)
常用 IN / ANY / ALL 配合:
sql
-- 查询"销售部"和"市场部"的所有员工
SELECT * FROM employee
WHERE dept_id IN (SELECT id FROM dept WHERE dept_name = '销售部' OR dept_name = '市场部');
9.3 行子查询(返回一行多列)
用行构造器 (值1, 值2) 或 ROW() 与之比较:
sql
-- 查询与"悟空"入职日期和工号都相同的员工
SELECT * FROM employee
WHERE (workno, entrydate) = (SELECT workno, entrydate FROM employee WHERE name = '悟空');
9.4 表子查询(返回多行多列)
把子查询结果当作一张临时表,与表连接或再查询:
sql
-- 查询每个部门年龄最大的员工信息
SELECT * FROM (
SELECT dept_id, MAX(age) AS max_age FROM employee GROUP BY dept_id
) t
JOIN employee e ON e.dept_id = t.dept_id AND e.age = t.max_age;
9.5 EXISTS 存在性子查询
sql
-- 查询"存在员工"的部门信息
SELECT * FROM dept d
WHERE EXISTS (SELECT 1 FROM employee e WHERE e.dept_id = d.id);
子查询有结果返回 TRUE,无结果返回 FALSE,常用于替代 IN 判断关联存在性。
10. 常用函数
10.1 字符串函数
| 函数 | 用法 | 功能 |
|---|---|---|
| CONCAT | CONCAT(str1, str2, ...) |
字符串拼接 |
| LENGTH | LENGTH(str) |
获取字符串长度(按字节) |
| CHAR_LENGTH | CHAR_LENGTH(str) |
按字符计长度 |
| UPPER / LOWER | UPPER(str) |
转大写 / 小写 |
| LPAD / RPAD | LPAD(str, n, pad) |
左/右填充到指定长度 |
| TRIM / LTRIM / RTRIM | TRIM(str) |
去除两端/左/右空格 |
| SUBSTRING | SUBSTRING(str, pos, len) |
截取子串(pos 从 1 开始) |
| REPLACE | REPLACE(str, from, to) |
替换子串 |
| INSTR | INSTR(str, substr) |
返回子串首次出现位置 |
10.2 数值函数
| 函数 | 用法 | 功能 |
|---|---|---|
| ABS | ABS(x) |
绝对值 |
| CEIL / FLOOR | CEIL(x) |
向上 / 向下取整 |
| ROUND | ROUND(x, d) |
四舍五入,d 为小数位数 |
| TRUNCATE | TRUNCATE(x, d) |
截断到 d 位小数(不四舍五入) |
| MOD | MOD(x, y) |
取余 |
| RAND | RAND() |
返回随机浮点数 [0,1) |
| UUID | UUID() |
生成全局唯一标识串 |
10.3 日期函数
| 函数 | 用法 | 功能 |
|---|---|---|
| NOW | NOW() |
返回当前日期和时间 |
| CURDATE / CURTIME | CURDATE() |
当前日期 / 当前时间 |
| YEAR / MONTH / DAY / HOUR / MINUTE / SECOND | YEAR(d) |
提取日期对应部分 |
| DATE_ADD | DATE_ADD(d, INTERVAL n 单位) |
日期加 n 个单位 |
| DATE_SUB | DATE_SUB(d, INTERVAL n DAY) |
日期减 n 个单位 |
| DATEDIFF | DATEDIFF(d1, d2) |
两日期相差天数(d1 - d2) |
| STR_TO_DATE | STR_TO_DATE(s, fmt) |
字符串按格式转日期 |
| DATE_FORMAT | DATE_FORMAT(d, fmt) |
日期按格式转字符串 |
sql
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY); -- 7 天后
SELECT DATEDIFF('2026-10-24', '2026-01-01'); -- 相差天数
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- 格式化输出
10.4 其他常用函数
| 函数 | 用法 | 功能 |
|---|---|---|
| IFNULL | IFNULL(x, 默认值) |
x 为 NULL 时返回默认值 |
| ISNULL | ISNULL(x) |
x 为 NULL 返回 1,否则 0 |
| IF | IF(cond, v1, v2) |
条件为真返回 v1,否则 v2 |
| CASE | CASE WHEN 条件 THEN 值 ... ELSE 值 END |
多分支映射 |
| GREATEST / LEAST | GREATEST(a,b,c) |
返回最大 / 最小值 |
sql
-- CASE 示例:按分数打等级
SELECT name, score,
CASE WHEN score >= 90 THEN '优秀'
WHEN score >= 60 THEN '及格'
ELSE '不及格' END AS 等级
FROM student;
11. 数据控制语言 DCL
11.1 管理用户
sql
-- 查询用户(用户信息存在 mysql 库的 user 表中)
USE mysql;
SELECT * FROM user;
-- 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
-- 修改密码(MySQL 5.7.6+)
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
-- 删除用户
DROP USER '用户名'@'主机名';
主机名 表示该用户允许从哪台机器登录:localhost 只允许本机,% 允许任意主机。
11.2 权限管理
sql
-- 查询用户权限
SHOW GRANTS FOR '用户名'@'主机名';
-- 授予权限
GRANT 权限列表 ON 数据库.表名 TO '用户名'@'主机名';
GRANT ALL ON *.* TO 'tomcat'@'%'; -- 授予所有库表的所有权限
-- 撤销权限
REVOKE 权限列表 ON 数据库.表名 FROM '用户名'@'主机名';
常见权限:ALL PRIVILEGES(所有)、SELECT、INSERT、UPDATE、DELETE、CREATE、DROP、GRANT OPTION(可转授权)。
安全实践:给业务账号只授予所需库表的最小权限,不要用 root 直连应用。
12. 事务(TCL)
12.1 概念
事务是一组要么全部成功、要么全部失败回滚的 SQL 操作集合,用于保证数据的一致性。典型场景:转账------扣款和入账必须同时成功或同时失败。
注意:只有 DML 语句(增删改) 的操作才纳入事务管理;DDL 操作会立即自动提交,无法回滚。MySQL 中 InnoDB 支持事务,MyISAM 不支持。
12.2 语法
sql
START TRANSACTION; -- 开启事务(或 BEGIN;)
UPDATE account SET money = money - 1000 WHERE name = 'A';
UPDATE account SET money = money + 1000 WHERE name = 'B';
COMMIT; -- 提交事务:两条更新永久生效
-- ROLLBACK; -- 回滚事务:撤销事务内所有未提交的修改
保存点(部分回滚):
sql
START TRANSACTION;
INSERT INTO account VALUES (5, 'E', 100);
SAVEPOINT s1; -- 设置保存点
INSERT INTO account VALUES (6, 'F', 200);
ROLLBACK TO s1; -- 只回滚到保存点,s1 之前的操作保留
COMMIT;
12.3 四大特性(ACID)
| 特性 | 说明 |
|---|---|
| 原子性 Atomicity | 事务是不可分割的整体,要么全成功,要么全失败 |
| 一致性 Consistency | 事务执行前后,数据从一个合法状态到另一个合法状态(如总额不变) |
| 隔离性 Isolation | 多个并发事务之间互不干扰 |
| 持久性 Durability | 事务一旦提交,修改永久保存到数据库 |
12.4 并发问题与隔离级别(了解)
并发可能带来:脏读 (读到别的事务未提交的数据)、不可重复读 (两次读取同一行数据不同,因别的事务 UPDATE)、幻读(两次查询行数不同,因别的事务 INSERT)。
sql
SELECT @@transaction_isolation; -- 查看隔离级别
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL 级别; -- 设置隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED(Oracle 默认) | ✗ | ✓ | ✓ |
| REPEATABLE READ(MySQL 默认) | ✗ | ✓* | |
| SERIALIZABLE | ✗ | ✗(并发性能最差) |
* InnoDB 通过 MVCC + 间隙锁在很大程度上避免了幻读。级别越高越安全、并发性能越差。
13. 附:SQL 语法执行顺序与学习路线
书写顺序 vs 执行顺序:
书写:SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT
执行:FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
理解执行顺序能解释很多现象:WHERE 里不能用 SELECT 定义的别名和聚合函数,HAVING 必须配合分组等。
建议后续学习路线(笔记尚未覆盖的进阶内容):
- 索引(INDEX)的创建与失效场景、EXPLAIN 执行计划
- 视图(VIEW)
- 存储过程、函数、触发器
- 锁机制与 InnoDB 存储引擎原理、MVCC
- SQL 优化与慢查询分析、备份恢复(mysqldump)