引言
在上一篇文章中,我们学习了 MySQL 的安装配置、基本 SQL 操作以及 C 语言连接数据库。本文将继续深入,讲解 MySQL 的核心高级特性:事务与隔离级别 、视图 、以及复杂查询的基础。这些是面试中的高频考点,也是实际项目开发中保证数据一致性的关键技术。

第一部分:MySQL 体系结构
一、整体架构

| 组件 | 功能 |
|---|---|
| 连接池 | 管理客户端连接,支持高并发 |
| SQL 解析器 | 词法分析、语法分析 |
| 优化器 | 选择最优执行计划(如索引选择) |
| 存储引擎 | 负责数据读写,可插拔(默认 InnoDB) |
| 文件系统 | 数据最终持久化到磁盘 |
第二部分:C 语言查询数据
一、完整查询流程
cpp
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
int main() {
// 1. 初始化连接句柄
MYSQL *conn = mysql_init(NULL);
if (conn == NULL) {
fprintf(stderr, "mysql_init 失败\n");
return -1;
}
// 2. 连接数据库
if (mysql_real_connect(conn, "127.0.0.1", "root", "123456",
"c1100db", 3306, NULL, 0) == NULL) {
fprintf(stderr, "连接失败: %s\n", mysql_error(conn));
mysql_close(conn);
return -1;
}
printf("数据库连接成功!\n");
// 3. 执行查询
const char *sql = "SELECT * FROM student";
if (mysql_query(conn, sql) != 0) {
fprintf(stderr, "查询失败: %s\n", mysql_error(conn));
mysql_close(conn);
return -1;
}
// 4. 获取结果集
MYSQL_RES *result = mysql_store_result(conn);
if (result == NULL) {
fprintf(stderr, "获取结果失败: %s\n", mysql_error(conn));
mysql_close(conn);
return -1;
}
// 5. 获取行数和列数
int num_rows = mysql_num_rows(result);
unsigned int num_fields = mysql_num_fields(result);
printf("行数: %d, 列数: %d\n", num_rows, num_fields);
// 6. 逐行逐列打印
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
for (unsigned int j = 0; j < num_fields; j++) {
printf("%s\t", row[j] ? row[j] : "NULL");
}
printf("\n");
}
// 7. 释放结果集和连接
mysql_free_result(result);
mysql_close(conn);
return 0;
}
编译运行:
gcc query.c -o query -lmysqlclient
./query
二、结果集处理要点
| API | 作用 | 返回值 |
|---|---|---|
mysql_store_result() |
获取结果集 | MYSQL_RES*,失败返回 NULL |
mysql_num_rows() |
获取行数 | int |
mysql_num_fields() |
获取列数 | unsigned int |
mysql_fetch_row() |
逐行读取 | MYSQL_ROW,读完返回 NULL |
mysql_free_result() |
释放结果集 | 无 |
重要提示:
-
MYSQL_ROW本质是char**,所有值都是字符串形式 -
数值型数据需要手动转换(如
atoi(row[0])) -
结果集用完后必须调用
mysql_free_result()释放
第三部分:事务
一、什么是事务
事务是一组 SQL 语句组成的原子操作单元,要么全部执行成功,要么全部回滚。

二、ACID 特性
| 特性 | 说明 | 举例 |
|---|---|---|
| 原子性 (Atomicity) | 事务是不可分割的最小单元 | 转账的两步要么都成,要么都不成 |
| 一致性 (Consistency) | 事务前后数据状态保持一致 | 转账前后总金额不变 |
| 隔离性 (Isolation) | 事务之间互不干扰 | A 转账时 B 看不到中间状态 |
| 持久性 (Durability) | 提交后数据永久保存 | 断电重启后数据不丢失 |
面试重点:能够解释 ACID 四个特性及其含义。
三、事务操作命令
cpp
-- 开启事务
BEGIN;
-- 或
START TRANSACTION;
-- 执行 SQL 操作...
INSERT INTO student VALUES (1005, '小王', 22);
UPDATE student SET age = 23 WHERE id = 1005;
-- 提交事务(永久保存)
COMMIT;
-- 回滚事务(撤销所有操作)
ROLLBACK;
四、C 语言中控制事务
cpp
// 开启事务
mysql_query(conn, "BEGIN");
// 执行多条 SQL
mysql_query(conn, "UPDATE account SET balance = balance - 1000 WHERE id = 1");
mysql_query(conn, "UPDATE account SET balance = balance + 1000 WHERE id = 2");
// 提交事务
mysql_query(conn, "COMMIT");
// 如果出错,回滚
// mysql_query(conn, "ROLLBACK");
第四部分:隔离级别
一、四种隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 隔离性 |
|---|---|---|---|---|
| READ UNCOMMITTED(未提交读) | ✅ | ✅ | ✅ | 最低 |
| READ COMMITTED(提交读) | ❌ | ✅ | ✅ | 中 |
| REPEATABLE READ(可重复读) | ❌ | ❌ | ✅ | 较高 |
| SERIALIZABLE(可串行化) | ❌ | ❌ | ❌ | 最高 |
三种并发问题:

二、查看和设置隔离级别
-- 查看当前会话隔离级别
SELECT @@transaction_isolation;
-- 查看全局隔离级别
SELECT @@global.transaction_isolation;
-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
三、可重复读 (REPEATABLE READ) 演示
这是 MySQL 默认的隔离级别。

四、提交读 (READ COMMITTED) 演示

五、隔离级别选择建议
| 场景 | 推荐级别 | 原因 |
|---|---|---|
| 银行转账 | SERIALIZABLE | 数据一致性要求极高 |
| 订单系统 | REPEATABLE READ | 默认,平衡性能与一致性 |
| 报表查询 | READ COMMITTED | 需要看到最新已提交数据 |
| 日志记录 | READ UNCOMMITTED | 性能优先,允许少量不一致 |
第五部分:视图
一、什么是视图
视图是虚拟表,不存储实际数据,数据来源于基本表的查询结果。

二、视图操作
cpp
-- 1. 创建视图
CREATE VIEW stu_view AS
SELECT id, name FROM student;
-- 2. 查询视图(和查表完全一样)
SELECT * FROM stu_view;
SELECT * FROM stu_view WHERE id > 1001;
-- 3. 查看所有表(含视图)
SHOW FULL TABLES;
-- Base Table → 基本表
-- View → 视图
-- 4. 删除视图(不影响基本表数据)
DROP VIEW stu_view;
三、视图的优缺点
| 优点 | 缺点 |
|---|---|
| 保护数据安全(隐藏敏感字段) | 不存储数据,每次查询需重新执行 |
| 简化复杂查询(封装多表联查) | 性能低于直接查询基本表 |
| 减少数据冗余 | 复杂视图可能降低查询效率 |
| 灵活调整展示格式 | 部分视图不可更新 |
第六部分:索引简介
索引是提升查询性能的核心手段,底层通常采用 B+树 数据结构。

cpp
-- 创建索引
CREATE INDEX idx_name ON student(name);
-- 查看索引
SHOW INDEX FROM student;
-- 删除索引
DROP INDEX idx_name ON student;
总结
一、事务与隔离级别
| 要点 | 说明 |
|---|---|
| 事务操作 | BEGIN → 执行SQL → COMMIT/ROLLBACK |
| ACID | 原子性、一致性、隔离性、持久性 |
| 默认隔离级别 | REPEATABLE READ(可重复读) |
| 隔离级别排序 | UNCOMMITTED < COMMITTED < REPEATABLE < SERIALIZABLE |
二、视图
cpp
CREATE VIEW 视图名 AS SELECT ...
DROP VIEW 视图名;
-- 视图不存数据,本质是封装的 SELECT 语句
三、C 语言查询数据
cpp
mysql_init → mysql_real_connect → mysql_query
→ mysql_store_result → mysql_fetch_row (循环)
→ mysql_free_result → mysql_close
四、一句话记忆
事务保证一组 SQL 要么全做要么全不做(ACID),隔离级别控制事务之间的可见性(默认可重复读),视图是封装好的虚拟表用于保护数据和简化查询,索引通过 B+树加速查询但增删改时会付出维护代价。