在实际的数据库应用中,数据通常分布在多个相关的表中,如何高效地从这些表中获取和处理数据是数据库开发中的重要课题。多表查询提供了强大的数据检索能力,通过连接查询和子查询,我们可以灵活地组合和筛选来自不同表的数据。同时,在进行数据修改操作时,事务管理机制确保了数据的一致性和完整性,是构建可靠数据库应用的基石。
本文将系统地介绍MySQL中的多表查询和事务管理。首先从多表查询的基本概念入手,详细讲解内连接、外连接等不同的连接查询方式,以及子查询的多种使用场景。接着深入探讨事务的概念、特性和隔离级别,帮助读者理解如何在实际开发中正确使用事务来保证数据的安全性。文章配有丰富的示例代码,便于读者实践和掌握这些重要的数据库操作技术。
建议读者在学习本文时,结合实际案例进行练习,特别是在理解不同类型的连接查询和事务隔离级别时,动手实践是加深理解的最好方式。
一、多表查询基础
1.1 概念
多表查询是指从多个表中获取数据的查询操作。在进行多表查询时会产生笛卡尔积,即两个集合的所有组合情况。为了得到有意义的查询结果,需要通过条件消除无用的数据。
1.2 基本语法
sql
SELECT 列名列表
FROM 表名列表
WHERE 条件;
1.3 示例数据准备
sql
-- 部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
-- 插入部门数据
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
-- 员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
);
-- 插入员工数据
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
('孙悟空','男',7200,'2013-02-24',1),
('猪八戒','男',3600,'2010-12-02',2),
('唐僧','男',9000,'2008-08-08',2),
('白骨精','女',5000,'2015-10-07',3),
('蜘蛛精','女',4500,'2011-03-14',1);
二、连接查询
2.1 内连接查询
2.1.1 隐式内连接
使用WHERE条件消除无用数据
sql
-- 查询所有员工信息和对应的部门信息
SELECT * FROM emp,dept
WHERE emp.dept_id = dept.id;
-- 使用别名优化查询(推荐)
SELECT
t1.name AS '姓名',
t1.gender AS '性别',
t2.name AS '部门'
FROM
emp t1,
dept t2
WHERE
t1.dept_id = t2.id;
2.1.2 显式内连接
使用INNER JOIN关键字,语法更直观
sql
-- 标准语法
SELECT * FROM emp
INNER JOIN dept ON emp.dept_id = dept.id;
-- INNER可以省略
SELECT * FROM emp
JOIN dept ON emp.dept_id = dept.id;
2.2 外连接查询
2.2.1 左外连接
查询左表所有数据以及其与右表的交集部分
sql
-- 查询所有员工信息及其部门信息(包括没有部门的员工)
SELECT t1.*, t2.name AS '部门名称'
FROM emp t1
LEFT JOIN dept t2
ON t1.dept_id = t2.id;
2.2.2 右外连接
查询右表所有数据以及其与左表的交集部分
sql
-- 查询所有部门信息及其员工信息(包括没有员工的部门)
SELECT t1.*, t2.name AS '员工姓名'
FROM dept t1
RIGHT JOIN emp t2
ON t2.dept_id = t1.id;
三、子查询
3.1 概念
子查询是指查询中嵌套查询,内部的查询称为子查询。
3.2 子查询分类
3.2.1 单行单列子查询
子查询结果为单个值,可以使用比较运算符
sql
-- 查询工资最高的员工信息
SELECT * FROM emp
WHERE salary = (SELECT MAX(salary) FROM emp);
-- 查询工资小于平均工资的员工
SELECT * FROM emp
WHERE salary < (SELECT AVG(salary) FROM emp);
3.2.2 多行单列子查询
子查询结果为一列多行,可以使用IN等运算符
sql
-- 查询财务部和市场部的所有员工信息
SELECT * FROM emp
WHERE dept_id IN (
SELECT id FROM dept
WHERE NAME IN ('财务部','市场部')
);
3.2.3 多行多列子查询
子查询结果可以作为一张虚拟表
sql
-- 查询2011-11-11后入职的员工信息和部门信息
SELECT * FROM dept t1,
(SELECT * FROM emp WHERE join_date > '2011-11-11') t2
WHERE t1.id = t2.dept_id;
四、事务管理
4.1 事务概念
事务是一组操作的集合,这些操作要么全部成功,要么全部失败。事务是数据库维护数据一致性的单位。
4.2 事务的基本操作
sql
-- 开启事务
START TRANSACTION;
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
4.3 事务示例
sql
-- 创建账户表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加测试数据
INSERT INTO account (NAME, balance)
VALUES ('张三', 1000), ('李四', 1000);
-- 转账操作
START TRANSACTION;
-- 张三账户减500
UPDATE account SET balance = balance - 500
WHERE NAME = '张三';
-- 李四账户加500
UPDATE account SET balance = balance + 500
WHERE NAME = '李四';
COMMIT;
4.4 事务的四大特性(ACID)
- 原子性(Atomicity):事务是不可分割的最小操作单位
- 一致性(Consistency):事务执行前后,数据保持一致
- 隔离性(Isolation):多个事务之间相互独立
- 持久性(Durability):事务一旦提交,结果永久保存
4.5 事务的隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 | 描述 |
---|---|---|---|---|
READ UNCOMMITTED | 是 | 是 | 是 | 读未提交 |
READ COMMITTED | 否 | 是 | 是 | 读已提交(Oracle默认) |
REPEATABLE READ | 否 | 否 | 是 | 可重复读(MySQL默认) |
SERIALIZABLE | 否 | 否 | 否 | 串行化 |
sql
-- 查询当前隔离级别
SELECT @@tx_isolation;
-- 设置隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
注意:隔离级别从低到高安全性越来越高,但性能越来越低。应根据实际业务需求选择合适的隔离级别。