Appearance
MyBatis 概述与架构
MyBatis 的前身是 Apache 的开源项目 iBatis,2010 年迁移到 Google Code 并更名为 MyBatis,2013 年迁移到 GitHub。它是一款持久层框架,封装了 JDBC 的操作,让开发者只需关注 SQL 本身。
一、MyBatis 是什么?
一句话:
MyBatis = SQL 映射框架 + 半自动 ORM
让你自由写 SQL,同时自动帮你搞定参数绑定和结果映射核心能力:
① 解耦 SQL 与 Java 代码
SQL 写在 XML 配置文件中,修改 SQL 不需要重新编译
② 自动映射
查询结果自动映射为 Java 对象(POJO)
③ 动态 SQL
根据条件动态拼接 SQL,告别 Java 里的字符串拼接
④ 数据库连接池
内置连接池,自动管理连接的获取和释放
⑤ 缓存支持
一级缓存(SqlSession 级别)+ 二级缓存(Mapper 级别)二、架构设计
MyBatis 架构分层:
┌─────────────────────────────────────────────────────┐
│ 接口层(API) │
│ SqlSession → 增删改查、提交回滚、获取 Mapper │
└──────────────────────┬──────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────┐
│ 数据处理层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 参数映射 │ │ SQL 解析 │ │ 结果映射 │ │
│ │parameter │ │ dynamic │ │ result │ │
│ │ mapping │ │ SQL │ │ mapping │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└──────────────────────┬──────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────┐
│ 基础支撑层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 连接池 │ │ 事务管理 │ │ 缓存模块 │ │
│ │ Pooled │ │ Tx │ │ Cache │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ 日志模块 │ │ 反射模块 │ │ 配置解析 │ │
│ │ Logging │ │Reflector │ │ XMLConfig │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘三、核心组件
3.1 SqlSessionFactory
作用:创建 SqlSession 的工厂,全局唯一,应用启动时创建
内部持有:
├─ Configuration(全局配置对象)
├─ 所有 Mapper 的映射信息
└─ 数据库环境配置
创建方式:
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);3.2 SqlSession
作用:执行 SQL、获取 Mapper、管理事务的会话对象
生命周期:
├─ 非线程安全 → 每个线程独立使用
├─ 每次请求创建 → 用完关闭
└─ 是请求/方法级别的作用域
核心方法:
selectOne / selectList → 查询
insert / update / delete → 增删改
commit / rollback → 事务控制
getMapper → 获取 Mapper 代理对象
close → 关闭会话3.3 Mapper 接口
作用:定义 SQL 操作的接口,MyBatis 动态代理生成实现
绑定方式:
① XML 映射:namespace = 接口全限定名
② 注解映射:@Select / @Insert / @Update / @Delete
示例:
public interface UserMapper {
User selectById(Long id);
}3.4 Executor(执行器)
作用:真正执行 SQL 的核心组件,SqlSession 内部委托给 Executor
三种类型:
SIMPLE → 简单执行器(默认),每次执行都创建新的 PreparedStatement
REUSE → 可重用执行器,缓存 PreparedStatement
BATCH → 批量执行器,用于批量操作
配置方式:
<settings>
<setting name="defaultExecutorType" value="REUSE"/>
</settings>四、工作原理(完整执行流程)
用户代码 MyBatis 内部
orderMapper.insert(order);
│
▼
┌─────────────────────────────────────────────────────────┐
│ ① MapperProxy(动态代理拦截) │
│ → 拦截接口方法调用 │
│ → 根据方法名找到对应的 MappedStatement │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ ② SqlSession(会话层) │
│ → insert/update/delete/select │
│ → 委托给 Executor 执行 │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ ③ Executor(执行器) │
│ → 处理缓存(一级/二级缓存) │
│ → 创建 StatementHandler │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ ④ StatementHandler(语句处理器) │
│ → ParameterHandler:参数绑定(?占位符赋值) │
│ → 执行 SQL(jdbc PreparedStatement.execute()) │
│ → ResultSetHandler:结果映射(ResultSet → Java 对象) │
└─────────────────────────────────────────────────────────┘速记:
一次 SQL 执行经过了 5 层:
接口代理 → SqlSession → Executor → StatementHandler → JDBC五、与 JDBC 的对比
| 步骤 | JDBC | MyBatis |
|---|---|---|
| 加载驱动 | Class.forName() | 配置文件指定 |
| 获取连接 | DriverManager.getConnection() | 自动从连接池获取 |
| 创建 Statement | Connection.createStatement() | 自动创建 |
| 设置参数 | stmt.setString(1, value) | 自动映射(#{} 占位符) |
| 执行 SQL | stmt.executeQuery() | 自动执行 |
| 处理结果 | while(rs.next()) | 自动映射到对象 |
| 关闭资源 | rs.close() stmt.close() conn.close() | 自动关闭 |
java
// JDBC 方式(繁琐)
public User findById(Long id) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url, user, password);
stmt = conn.prepareStatement("SELECT * FROM user WHERE id = ?");
stmt.setLong(1, id);
rs = stmt.executeQuery();
if (rs.next()) {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
return user;
}
return null;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (rs != null) try { rs.close(); } catch (SQLException ignored) {}
if (stmt != null) try { stmt.close(); } catch (SQLException ignored) {}
if (conn != null) try { conn.close(); } catch (SQLException ignored) {}
}
}
// MyBatis 方式(简洁)
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);
}六、面试要点
| 问题 | 答案要点 |
|---|---|
| MyBatis 是什么? | 半自动 ORM 持久层框架,SQL 与 Java 分离 |
| 核心组件有哪些? | SqlSessionFactory、SqlSession、Mapper、Executor |
| SqlSession 生命周期? | 非线程安全,请求级别,用完关闭 |
| 执行流程是怎样的? | MapperProxy → SqlSession → Executor → StatementHandler → JDBC |
| 和 Hibernate 的区别? | MyBatis 手写 SQL 更灵活,Hibernate 全自动映射 |
