目录
[一、MySQL 常用函数](#一、MySQL 常用函数)
[1. 字符串函数](#1. 字符串函数)
[1.1 基本字符串操作](#1.1 基本字符串操作)
[1.2 字符串截取与处理](#1.2 字符串截取与处理)
[1.3 字符串搜索与替换](#1.3 字符串搜索与替换)
[2. 数值函数](#2. 数值函数)
[2.1 基本数学运算](#2.1 基本数学运算)
[2.2 数学计算](#2.2 数学计算)
[2.3 随机数与符号](#2.3 随机数与符号)
[3. 日期时间函数](#3. 日期时间函数)
[3.1 获取当前时间](#3.1 获取当前时间)
[3.2 日期时间计算](#3.2 日期时间计算)
[3.3 日期时间提取](#3.3 日期时间提取)
[3.4 日期时间格式化](#3.4 日期时间格式化)
[4. 条件函数](#4. 条件函数)
[4.1 流程控制函数](#4.1 流程控制函数)
[4.2 聚合函数](#4.2 聚合函数)
[5. 窗口函数 (MySQL 8.0+)](#5. 窗口函数 (MySQL 8.0+))
[6. JSON 函数 (MySQL 5.7+)](#6. JSON 函数 (MySQL 5.7+))
[7. 系统信息函数](#7. 系统信息函数)
[8. 加密函数](#8. 加密函数)
[二、MySQL 约束](#二、MySQL 约束)
[1. 主键约束 (PRIMARY KEY)](#1. 主键约束 (PRIMARY KEY))
[1.1 基本用法](#1.1 基本用法)
[1.2 修改表添加主键](#1.2 修改表添加主键)
[1.3 自增主键](#1.3 自增主键)
[2. 外键约束 (FOREIGN KEY)](#2. 外键约束 (FOREIGN KEY))
[2.1 基本用法](#2.1 基本用法)
[2.2 级联操作](#2.2 级联操作)
[2.3 修改表添加外键](#2.3 修改表添加外键)
[3. 唯一约束 (UNIQUE)](#3. 唯一约束 (UNIQUE))
[3.1 基本用法](#3.1 基本用法)
[3.2 多列组合唯一](#3.2 多列组合唯一)
[3.3 修改表添加唯一约束](#3.3 修改表添加唯一约束)
[4. 非空约束 (NOT NULL)](#4. 非空约束 (NOT NULL))
[4.1 基本用法](#4.1 基本用法)
[4.2 修改表添加非空约束](#4.2 修改表添加非空约束)
[5. 默认值约束 (DEFAULT)](#5. 默认值约束 (DEFAULT))
[5.1 基本用法](#5.1 基本用法)
[5.2 修改表添加默认值](#5.2 修改表添加默认值)
[6. 检查约束 (CHECK)](#6. 检查约束 (CHECK))
[6.1 基本用法](#6.1 基本用法)
[6.2 命名检查约束](#6.2 命名检查约束)
[6.3 修改表添加检查约束](#6.3 修改表添加检查约束)
[7. 约束管理](#7. 约束管理)
[7.1 查看约束](#7.1 查看约束)
[7.2 删除约束](#7.2 删除约束)
[1. 内连接 (INNER JOIN)](#1. 内连接 (INNER JOIN))
[2. 左外连接 (LEFT JOIN)](#2. 左外连接 (LEFT JOIN))
[3. 右外连接 (RIGHT JOIN)](#3. 右外连接 (RIGHT JOIN))
[4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟](#4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟)
[5. 交叉连接 (CROSS JOIN)](#5. 交叉连接 (CROSS JOIN))
[6. 自连接 (SELF JOIN)](#6. 自连接 (SELF JOIN))
[7. 自然连接 (NATURAL JOIN)](#7. 自然连接 (NATURAL JOIN))
[8. USING 子句](#8. USING 子句)
[9. 子查询](#9. 子查询)
[9.1 WHERE子句中的子查询](#9.1 WHERE子句中的子查询)
[9.2 FROM子句中的子查询(派生表)](#9.2 FROM子句中的子查询(派生表))
[9.3 SELECT子句中的子查询(标量子查询)](#9.3 SELECT子句中的子查询(标量子查询))
[9.4 HAVING子句中的子查询](#9.4 HAVING子句中的子查询)
[9.5 EXISTS和NOT EXISTS子查询](#9.5 EXISTS和NOT EXISTS子查询)
[10. 集合操作](#10. 集合操作)
[10.1 UNION 和 UNION ALL](#10.1 UNION 和 UNION ALL)
[10.2 INTERSECT (MySQL 8.0.31+)](#10.2 INTERSECT (MySQL 8.0.31+))
[10.3 EXCEPT/MINUS (MySQL 8.0.31+)](#10.3 EXCEPT/MINUS (MySQL 8.0.31+))
[1. 事务的基本特性 (ACID)](#1. 事务的基本特性 (ACID))
[2. 事务控制语句](#2. 事务控制语句)
[3. 事务隔离级别](#3. 事务隔离级别)
[4. 事务并发问题](#4. 事务并发问题)
(2)不可重复读 (Non-repeatable Read)
[5. 保存点 (SAVEPOINT)](#5. 保存点 (SAVEPOINT))
一、MySQL 常用函数
MySQL 提供了丰富的内置函数,可以用于数据处理、计算和转换。这些函数主要分为以下几类:
1. 字符串函数
1.1 基本字符串操作
sql
-- 连接字符串
SELECT CONCAT('Hello', ' ', 'World'); -- 输出: Hello World
SELECT CONCAT_WS('-', '2023', '01', '01'); -- 用分隔符连接: 2023-01-01
-- 字符串长度
SELECT LENGTH('MySQL'); -- 字节数: 5
SELECT CHAR_LENGTH('MySQL'); -- 字符数: 5
-- 大小写转换
SELECT UPPER('mysql'); -- MYSQL
SELECT LOWER('MySQL'); -- mysql
1.2 字符串截取与处理
sql
-- 截取字符串
SELECT SUBSTRING('MySQL', 2, 3); -- ySQ (从第2个字符开始,取3个)
SELECT LEFT('MySQL', 2); -- My
SELECT RIGHT('MySQL', 3); -- SQL
-- 去除空格
SELECT TRIM(' MySQL '); -- 'MySQL'
SELECT LTRIM(' MySQL'); -- 'MySQL'
SELECT RTRIM('MySQL '); -- 'MySQL'
-- 填充字符串
SELECT LPAD('5', 3, '0'); -- 005
SELECT RPAD('Hi', 5, '!'); -- Hi!!!
1.3 字符串搜索与替换
sql
-- 查找位置
SELECT INSTR('MySQL', 'SQL'); -- 3 (SQL在MySQL中的位置)
SELECT LOCATE('SQL', 'MySQL'); -- 3
-- 替换字符串
SELECT REPLACE('MySQL', 'SQL', 'Database'); -- MyDatabase
-- 正则表达式
SELECT 'MySQL' REGEXP '^My'; -- 1 (匹配成功)
SELECT REGEXP_REPLACE('abc123', '[0-9]', 'X'); -- abcXXX
2. 数值函数
2.1 基本数学运算
sql
-- 四舍五入
SELECT ROUND(3.14159, 2); -- 3.14
SELECT ROUND(123.456, -1); -- 120 (小数点左侧舍入)
-- 取整
SELECT CEIL(3.14); -- 4 (向上取整)
SELECT FLOOR(3.14); -- 3 (向下取整)
SELECT TRUNCATE(3.14159, 2); -- 3.14 (截断)
-- 绝对值
SELECT ABS(-10); -- 10
2.2 数学计算
sql
-- 幂运算
SELECT POWER(2, 3); -- 8 (2的3次方)
SELECT SQRT(16); -- 4 (平方根)
-- 对数
SELECT LOG(2, 8); -- 3 (以2为底8的对数)
SELECT LN(10); -- 自然对数
SELECT LOG10(100); -- 2
-- 三角函数
SELECT SIN(PI()/2); -- 1
SELECT COS(0); -- 1
SELECT TAN(PI()/4); -- 约等于1
2.3 随机数与符号
sql
-- 随机数
SELECT RAND(); -- 0到1之间的随机数
SELECT FLOOR(1 + RAND() * 10); -- 1-10的随机整数
-- 符号判断
SELECT SIGN(-10); -- -1
SELECT SIGN(0); -- 0
SELECT SIGN(10); -- 1
3. 日期时间函数
3.1 获取当前时间
sql
SELECT NOW(); -- 当前日期和时间 (2023-01-01 12:34:56)
SELECT CURDATE(); -- 当前日期 (2023-01-01)
SELECT CURTIME(); -- 当前时间 (12:34:56)
SELECT UNIX_TIMESTAMP(); -- 当前UNIX时间戳
3.2 日期时间计算
sql
-- 日期加减
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); -- 加1天
SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH); -- 减1个月
SELECT NOW() + INTERVAL 1 HOUR; -- 加1小时
-- 日期差
SELECT DATEDIFF('2023-12-31', '2023-01-01'); -- 364 (天数差)
SELECT TIMESTAMPDIFF(MONTH, '2023-01-01', '2023-12-31'); -- 11 (月数差)
3.3 日期时间提取
sql
-- 提取日期部分
SELECT YEAR(NOW()); -- 2023
SELECT MONTH(NOW()); -- 1-12
SELECT DAY(NOW()); -- 1-31
SELECT HOUR(NOW()); -- 0-23
SELECT MINUTE(NOW()); -- 0-59
SELECT SECOND(NOW()); -- 0-59
-- 星期和季度
SELECT DAYNAME(NOW()); -- Monday
SELECT DAYOFWEEK(NOW()); -- 1=周日, 2=周一,...,7=周六
SELECT QUARTER(NOW()); -- 1-4
3.4 日期时间格式化
sql
-- 格式化日期
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d'); -- 2023-01-01
SELECT DATE_FORMAT(NOW(), '%H:%i:%s'); -- 12:34:56
SELECT DATE_FORMAT(NOW(), '%W, %M %e, %Y'); -- Sunday, January 1, 2023
-- 解析日期字符串
SELECT STR_TO_DATE('01-01-2023', '%d-%m-%Y'); -- 2023-01-01
4. 条件函数
4.1 流程控制函数
sql
-- IF函数
SELECT IF(1 > 0, 'True', 'False'); -- True
SELECT IFNULL(NULL, 'Default'); -- Default
SELECT NULLIF(10, 10); -- NULL (两值相等返回NULL)
-- CASE WHEN
SELECT
score,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
ELSE 'D'
END AS grade
FROM students;
4.2 聚合函数
sql
-- 基本聚合
SELECT COUNT(*) FROM users; -- 记录数
SELECT AVG(price) FROM products; -- 平均值
SELECT SUM(quantity) FROM order_items; -- 总和
SELECT MAX(salary) FROM employees; -- 最大值
SELECT MIN(age) FROM customers; -- 最小值
-- 分组聚合
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 5000;
5. 窗口函数 (MySQL 8.0+)
sql
-- 排名函数
SELECT
name, salary,
RANK() OVER (ORDER BY salary DESC) AS rank,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;
-- 分区计算
SELECT
department_id, name, salary,
AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary
FROM employees;
-- 累计计算
SELECT
order_date, amount,
SUM(amount) OVER (ORDER BY order_date) AS running_total
FROM orders;
6. JSON 函数 (MySQL 5.7+)
sql
-- 创建JSON
SELECT JSON_OBJECT('name', 'John', 'age', 30);
SELECT JSON_ARRAY(1, 'a', TRUE, NULL);
-- 提取JSON值
SELECT JSON_EXTRACT('{"name": "John", "age": 30}', '$.name'); -- "John"
SELECT JSON_UNQUOTE(JSON_EXTRACT('{"name": "John"}', '$.name')); -- John
-- 修改JSON
SELECT JSON_SET('{"name": "John"}', '$.age', 30); -- {"name": "John", "age": 30}
SELECT JSON_REMOVE('{"name": "John", "age": 30}', '$.age'); -- {"name": "John"}
7. 系统信息函数
sql
-- 数据库信息
SELECT DATABASE(); -- 当前数据库名
SELECT USER(); -- 当前用户
SELECT VERSION(); -- MySQL版本
-- 连接信息
SELECT CONNECTION_ID(); -- 连接ID
SELECT LAST_INSERT_ID(); -- 最后插入的ID
-- 性能分析
SELECT BENCHMARK(1000000, MD5('test')); -- 执行MD5 100万次
8. 加密函数
sql
-- 哈希函数
SELECT MD5('password'); -- 32字符MD5哈希
SELECT SHA1('password'); -- 40字符SHA1哈希
SELECT SHA2('password', 256); -- 64字符SHA256哈希
-- 加密解密
SELECT AES_ENCRYPT('secret', 'key');
SELECT AES_DECRYPT(encrypted_data, 'key');
-- 密码函数
SELECT PASSWORD('mypass'); -- 已废弃,不推荐使用
二、MySQL 约束
约束是用于限制表中数据类型的规则,确保数据的准确性和可靠性。MySQL 支持多种约束类型,以下是简要介绍:
1. 主键约束 (PRIMARY KEY)
1.1 基本用法
sql
-- 创建表时定义单列主键
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50) NOT NULL
);
-- 创建表时定义多列组合主键
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
1.2 修改表添加主键
sql
ALTER TABLE employees ADD PRIMARY KEY (emp_id);
1.3 自增主键
sql
CREATE TABLE products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL
);
2. 外键约束 (FOREIGN KEY)
2.1 基本用法
sql
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
2.2 级联操作
sql
CREATE TABLE order_items (
item_id INT PRIMARY KEY,
order_id INT,
product_id INT,
FOREIGN KEY (order_id) REFERENCES orders(order_id)
ON DELETE CASCADE -- 主表删除时级联删除
ON UPDATE CASCADE, -- 主表更新时级联更新
FOREIGN KEY (product_id) REFERENCES products(product_id)
ON DELETE SET NULL -- 主表删除时设为NULL
);
2.3 修改表添加外键
sql
ALTER TABLE employees
ADD CONSTRAINT fk_dept
FOREIGN KEY (department_id) REFERENCES departments(dept_id);
3. 唯一约束 (UNIQUE)
3.1 基本用法
sql
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20),
CONSTRAINT uc_phone UNIQUE (phone) -- 命名约束
);
3.2 多列组合唯一
sql
CREATE TABLE class_registry (
student_id INT,
class_id INT,
semester VARCHAR(10),
UNIQUE (student_id, class_id, semester)
);
3.3 修改表添加唯一约束
sql
ALTER TABLE products ADD UNIQUE (product_code);
4. 非空约束 (NOT NULL)
4.1 基本用法
sql
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);
4.2 修改表添加非空约束
sql
ALTER TABLE employees MODIFY COLUMN hire_date DATE NOT NULL;
5. 默认值约束 (DEFAULT)
5.1 基本用法
sql
CREATE TABLE orders (
order_id INT PRIMARY KEY,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'Pending',
total_amount DECIMAL(10,2) DEFAULT 0.00
);
5.2 修改表添加默认值
sql
ALTER TABLE products
ALTER COLUMN stock SET DEFAULT 0;
6. 检查约束 (CHECK)
6.1 基本用法
sql
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
salary DECIMAL(10,2) CHECK (salary > 0),
age INT CHECK (age >= 18 AND age <= 65),
gender VARCHAR(10) CHECK (gender IN ('Male', 'Female', 'Other'))
);
6.2 命名检查约束
sql
CREATE TABLE products (
product_id INT PRIMARY KEY,
price DECIMAL(10,2),
discount DECIMAL(10,2),
CONSTRAINT chk_price CHECK (price > 0),
CONSTRAINT chk_discount CHECK (discount >= 0 AND discount <= price)
);
6.3 修改表添加检查约束
sql
ALTER TABLE employees
ADD CONSTRAINT chk_salary CHECK (salary > 0);
7. 约束管理
7.1 查看约束
sql
-- 查看表的所有约束
SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = 'your_database' AND TABLE_NAME = 'your_table';
-- 查看外键约束
SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = 'your_database';
7.2 删除约束
sql
-- 删除主键
ALTER TABLE users DROP PRIMARY KEY;
-- 删除外键
ALTER TABLE orders DROP FOREIGN KEY fk_customer;
-- 删除唯一约束
ALTER TABLE employees DROP INDEX uc_phone;
-- 删除检查约束 (MySQL 8.0.16+)
ALTER TABLE employees DROP CHECK chk_salary;
三、多表查询
1. 内连接 (INNER JOIN)
sql
-- 基本内连接
SELECT
e.emp_id,
e.emp_name,
d.dept_name
FROM
employees e
INNER JOIN
departments d ON e.dept_id = d.dept_id;
-- 多表内连接
SELECT
o.order_id,
c.customer_name,
p.product_name,
oi.quantity
FROM
orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id;
2. 左外连接 (LEFT JOIN)
sql
-- 保留左表所有记录
SELECT
d.dept_name,
e.emp_name
FROM
departments d
LEFT JOIN
employees e ON d.dept_id = e.dept_id;
3. 右外连接 (RIGHT JOIN)
sql
-- 保留右表所有记录
SELECT
e.emp_name,
d.dept_name
FROM
employees e
RIGHT JOIN
departments d ON e.dept_id = d.dept_id;
4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟
sql
-- 使用UNION模拟全连接
SELECT
e.emp_name,
d.dept_name
FROM
employees e
LEFT JOIN
departments d ON e.dept_id = d.dept_id
UNION
SELECT
e.emp_name,
d.dept_name
FROM
employees e
RIGHT JOIN
departments d ON e.dept_id = d.dept_id
WHERE
e.dept_id IS NULL;
5. 交叉连接 (CROSS JOIN)
sql
-- 笛卡尔积
SELECT
e.emp_name,
p.project_name
FROM
employees e
CROSS JOIN
projects p;
6. 自连接 (SELF JOIN)
sql
-- 查找员工及其经理
SELECT
e1.emp_name AS employee,
e2.emp_name AS manager
FROM
employees e1
LEFT JOIN
employees e2 ON e1.manager_id = e2.emp_id;
-- 查找同一部门的员工对
SELECT
a.emp_name AS employee1,
b.emp_name AS employee2,
a.dept_id
FROM
employees a
JOIN
employees b ON a.dept_id = b.dept_id
WHERE
a.emp_id < b.emp_id;
7. 自然连接 (NATURAL JOIN)
sql
-- 自动匹配相同名称的列
SELECT
e.emp_name,
d.dept_name
FROM
employees e
NATURAL JOIN
departments d;
8. USING 子句
sql
-- 简化连接条件
SELECT
e.emp_name,
d.dept_name
FROM
employees e
JOIN
departments d USING (dept_id);
9. 子查询
9.1 WHERE子句中的子查询
(1)标量子查询(返回单个值)
sql
-- 查询高于平均工资的员工
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- 查询最后入职的员工
SELECT emp_name, hire_date
FROM employees
WHERE hire_date = (SELECT MAX(hire_date) FROM employees);
(2)列子查询(返回单列多行)
sql
-- 使用IN操作符
SELECT emp_name, dept_id
FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = 'New York');
-- 使用ANY/SOME操作符
SELECT emp_name, salary
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE dept_id = 10);
-- 使用ALL操作符
SELECT emp_name, salary
FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 10);
(3)行子查询(返回单行多列)
sql
-- 查询与特定员工工资和部门相同的其他员工
SELECT emp_name, salary, dept_id
FROM employees
WHERE (salary, dept_id) = (SELECT salary, dept_id FROM employees WHERE emp_id = 100);
9.2 FROM子句中的子查询(派生表)
sql
-- 计算每个部门的平均工资,然后查询高于公司平均工资的部门
SELECT d.dept_name, dept_avg.avg_salary
FROM departments d
JOIN (
SELECT dept_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id
) dept_avg ON d.dept_id = dept_avg.dept_id
WHERE dept_avg.avg_salary > (SELECT AVG(salary) FROM employees);
-- 使用派生表进行分页
SELECT *
FROM (
SELECT emp_id, emp_name, salary
FROM employees
ORDER BY salary DESC
LIMIT 10
) AS top_earners;
9.3 SELECT子句中的子查询(标量子查询)
sql
-- 查询员工信息及其部门平均工资
SELECT
emp_id,
emp_name,
salary,
(SELECT AVG(salary) FROM employees e2 WHERE e2.dept_id = e1.dept_id) AS dept_avg_salary,
salary - (SELECT AVG(salary) FROM employees e2 WHERE e2.dept_id = e1.dept_id) AS diff_from_avg
FROM employees e1;
-- 查询产品信息及订单数量
SELECT
p.product_id,
p.product_name,
(SELECT COUNT(*) FROM order_items oi WHERE oi.product_id = p.product_id) AS order_count
FROM products p;
9.4 HAVING子句中的子查询
sql
-- 查询平均工资高于公司平均工资的部门
SELECT
dept_id,
AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);
-- 查询订单数量超过客户平均订单数的客户
SELECT
customer_id,
COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > (SELECT AVG(order_count)
FROM (SELECT COUNT(*) AS order_count
FROM orders
GROUP BY customer_id) AS counts);
9.5 EXISTS和NOT EXISTS子查询
sql
-- 查询有订单的客户
SELECT customer_name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);
-- 查询没有订单的客户
SELECT customer_name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);
-- 查询购买了所有产品的客户
SELECT customer_name
FROM customers c
WHERE NOT EXISTS (
SELECT product_id
FROM products p
WHERE NOT EXISTS (
SELECT 1
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.customer_id = c.customer_id
AND oi.product_id = p.product_id
)
);
10. 集合操作
10.1 UNION 和 UNION ALL
sql
-- 合并结果集 (去重)
SELECT product_id FROM current_products
UNION
SELECT product_id FROM discontinued_products;
-- 合并结果集 (保留重复)
SELECT product_id FROM current_products
UNION ALL
SELECT product_id FROM discontinued_products;
10.2 INTERSECT (MySQL 8.0.31+)
sql
-- 交集
SELECT customer_id FROM premium_customers
INTERSECT
SELECT customer_id FROM active_customers;
10.3 EXCEPT/MINUS (MySQL 8.0.31+)
sql
-- 差集
SELECT employee_id FROM all_employees
EXCEPT
SELECT employee_id FROM current_employees;
四、事务 (Transaction)
1. 事务的基本特性 (ACID)
-
原子性 (Atomicity): 事务是不可分割的工作单位。
-
一致性 (Consistency): 事务执行前后数据库保持一致状态。
-
隔离性 (Isolation): 多个事务并发执行时互不干扰。
-
持久性 (Durability): 事务提交后对数据库的改变是永久的。
2. 事务控制语句
sql
-- 开始事务
START TRANSACTION;
-- 执行SQL语句
INSERT INTO accounts (user_id, balance) VALUES (1, 1000);
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
3. 事务隔离级别
sql
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别(会话级)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置隔离级别(全局)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 四种隔离级别
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- MySQL默认
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
四种隔离级别比较:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
---|---|---|---|---|
READ UNCOMMITTED | 可能 | 可能 | 可能 | 最高 |
READ COMMITTED | 不可能 | 可能 | 可能 | 高 |
REPEATABLE READ(默认) | 不可能 | 不可能 | 可能 | 中 |
SERIALIZABLE | 不可能 | 不可能 | 不可能 | 低 |
4. 事务并发问题
(1)脏读 (Dirty Read)
读取到其他事务未提交的数据。
sql
-- 事务A
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT * FROM accounts WHERE user_id = 1; -- 可能读取到事务B未提交的数据
-- 事务B
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 尚未提交
(2)不可重复读 (Non-repeatable Read)
同一事务内多次读取同一数据结果不同。
sql
-- 事务A
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT * FROM accounts WHERE user_id = 1; -- 第一次读取
-- 事务B提交了更新
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
COMMIT;
SELECT * FROM accounts WHERE user_id = 1; -- 第二次读取结果不同
(3)幻读 (Phantom Read)
同一事务内多次查询返回的结果集不同。
sql
-- 事务A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM accounts WHERE balance > 1000; -- 返回10条记录
-- 事务B插入新记录并提交
INSERT INTO accounts VALUES (11, '新用户', 1500);
COMMIT;
SELECT * FROM accounts WHERE balance > 1000; -- 返回11条记录
5. 保存点 (SAVEPOINT)
sql
START TRANSACTION;
INSERT INTO orders (order_id, user_id) VALUES (1, 1);
SAVEPOINT savepoint1;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 如果出现问题可以回滚到保存点
ROLLBACK TO savepoint1;
COMMIT;