一、MyBatis 执行流程
MyBatis 是 Java 持久层框架,它负责把 Java 代码中的数据库操作,转化为可执行的 SQL 并与数据库交互。
1. 读取配置文件
- 读取 MyBatis 全局配置文件(
sqlMapConfig.xml/mybatis-config.xml)和所有 Mapper 映射文件。 - 全局配置文件:包含数据库连接信息、事务、别名、日志、插件等配置。
- Mapper 映射文件:包含具体 SQL 语句、参数映射、结果集映射规则。
2. 构建SqlSessionFactory对象
- MyBatis 通过配置文件解析器,将所有配置信息加载到内存,构建出
SqlSessionFactory。 SqlSessionFactory是工厂类,全局唯一,负责创建SqlSession,它相当于数据库连接池的入口。
3. 创建SqlSession对象
- 由
SqlSessionFactory创建SqlSession对象,它代表一次数据库会话,包含了数据库连接、事务控制、执行 SQL 的能力。 SqlSession是 MyBatis 操作数据库的核心对象,是非线程安全的,每次数据库操作都应创建独立实例。
4. 获取 Mapper 代理对象
- 通过
SqlSession.getMapper(XXXMapper.class)获取 Mapper 接口的代理对象。 - 代理对象会自动绑定 Mapper 映射文件中的 SQL 语句,让开发者可以通过调用接口方法执行数据库操作,无需手动写 JDBC 代码。
5. 执行数据库操作
- 调用 Mapper 接口的方法时,代理对象会解析对应的 SQL 语句,完成参数绑定、SQL 预编译,再通过
SqlSession执行增删改查操作。 SqlSession内部封装了 JDBC 的Connection、Statement,与数据库建立连接并执行 SQL。
6. 结果映射与会话关闭
- 数据库返回的结果集,会根据 Mapper 映射文件中的规则,自动映射为 Java 对象。
- 操作完成后,关闭
SqlSession,释放数据库连接资源。
二、MySQL 执行流程(以 MyBatis 场景为例)
MyBatis 生成的 SQL 最终会发送给 MySQL 服务器,MySQL 内部会按以下流程处理请求:
1. SQL 与参数拼接(MyBatis 层准备)
- MyBatis 将用户传入的参数,与 Mapper 映射文件中的 SQL 模板进行预编译拼接(
#{}会生成预编译语句,防止 SQL 注入),生成完整可执行的 SQL 语句。
2. 连接器(Connection)处理
- MySQL 服务器接收客户端(MyBatis)的连接请求,建立 TCP 连接,分配线程处理该请求。
- 进行用户身份验证、权限校验,确认该用户有执行当前 SQL 的权限。
3. 查询缓存(可选)
- MySQL 会先检查查询缓存(MySQL 8.0 已移除该功能),如果缓存中存在完全相同的 SQL 及其结果,直接返回缓存数据,跳过后续流程。
4. SQL 解析与预处理
- 解析器对 SQL 语句进行词法、语法分析,生成抽象语法树(AST),验证 SQL 语法是否合法。
- 预处理阶段会检查表、字段是否存在,用户权限是否匹配。
5. 查询优化器(Optimizer)优化
- 优化器根据统计信息,生成多种执行方案,选择最优的执行计划(比如选择合适的索引、决定表连接顺序)。
- 生成执行计划后,将其传递给执行器。
6. 执行器(Executor)执行 SQL
- 执行器调用存储引擎的接口,按照优化后的执行计划,向存储引擎请求数据。
- 对于 DML 语句(增删改),会执行对应的写操作;对于 DQL 语句(查询),会读取数据。
7. 存储引擎处理
- 以 InnoDB 为例:
- 优先从缓冲池(Buffer Pool)中读取数据页,若不存在则从磁盘加载数据页到缓冲池。
- 执行事务操作,记录 Redo Log(重做日志)和 Undo Log(回滚日志),保证事务的 ACID 特性。
- 写操作会先写入缓冲池,再通过刷盘机制持久化到磁盘。
8. 结果返回
- 存储引擎将数据返回给执行器,执行器将结果集返回给客户端(MyBatis)。
- MyBatis 再将结果集映射为 Java 对象,完成整个流程。
三、面试高频考点补充
#{}与${}的区别#{}:预编译处理,SQL 中的参数会被替换为?,使用 PreparedStatement 赋值,防止 SQL 注入,推荐使用。${}:直接字符串拼接,不会预编译,存在 SQL 注入风险,仅适用于表名、列名等动态场景。
MyBatis 一级缓存与二级缓存
- 一级缓存:
SqlSession级别缓存,默认开启,同一会话内相同查询直接从缓存取数据,会话关闭则缓存失效。 - 二级缓存:
Mapper级别缓存,跨SqlSession共享,需手动配置开启,适用于多会话场景。
- 一级缓存:
MySQL 预编译的作用
- 预编译语句(PreparedStatement)会将 SQL 模板提前发送给数据库,后续仅发送参数,数据库可复用执行计划,提升效率,同时防止 SQL 注入。