MyBatis的工作原理
MyBatis 是一个基于 SQL 映射 的持久层框架,其核心设计目标是 简化数据库操作,同时保留开发者对 SQL 的完全控制权。以下是其工作原理的分步解析:
目录
1. 核心组件与流程
1.1 配置阶段
2. 关键机制
2.1 参数处理
2.2 结果映射
3. 与 Spring 集成
4. 优势与适用场景
5. 总结:MyBatis 工作原理图
1. 核心组件与流程
1.1 配置阶段
- 配置文件:通过
mybatis-config.xml
配置数据源、事务管理器、类型别名等全局设置。 - Mapper 映射文件:定义 SQL 语句、参数映射(
#{}
/${}
)和结果映射(resultMap
)。
<!-- 示例:UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper"><select id="getUserById" resultType="User">SELECT * FROM users WHERE id = #{id}</select>
</mapper>
1.2 初始化阶段
- SqlSessionFactory 构建:读取配置文件,创建
SqlSessionFactory
(单例)。
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.3 执行阶段
-
获取 SqlSession:通过
SqlSessionFactory
打开一个SqlSession
(线程不安全,需短生命周期)。
try (SqlSession session = sqlSessionFactory.openSession()) {UserMapper mapper = session.getMapper(UserMapper.class);User user = mapper.getUserById(1);
}
-
动态代理生成 Mapper 接口实现:
- MyBatis 通过 JDK 动态代理为
UserMapper
接口生成实现类。 - 方法调用(如
getUserById
)会被拦截,解析为对应的 SQL 语句。
- MyBatis 通过 JDK 动态代理为
-
SQL 执行与结果映射:
- 参数替换:将方法参数(如
id=1
)替换到 SQL 中的#{}
占位符。 - 执行 SQL:通过 JDBC 执行预编译语句,获取
ResultSet
。 - 结果映射:将
ResultSet
的列映射到 Java 对象的属性(支持自动映射或resultMap
自定义映射)。
- 参数替换:将方法参数(如
<resultMap id="userResultMap" type="User"><id property="id" column="user_id"/><result property="username" column="user_name"/>
</resultMap>
2. 关键机制
2.1 参数处理
#{}
占位符:使用PreparedStatement
防止 SQL 注入,自动处理类型转换。${}
替换符:直接拼接 SQL 字符串,需谨慎使用(存在注入风险)。
2.2 结果映射
- 自动映射:根据列名与属性名的驼峰命名规则自动匹配(如
user_name
→userName
)。 - 复杂类型映射:通过
association
(一对一)和collection
(一对多)处理关联查询。
<resultMap id="orderResultMap" type="Order"><association property="user" javaType="User" resultMap="userResultMap"/><collection property="items" ofType="Item" resultMap="itemResultMap"/>
</resultMap>
2.3 动态 SQL
- 通过
<if>
,<choose>
,<foreach>
等标签构建灵活的 SQL 语句。
<select id="findUsers" resultType="User">SELECT * FROM users<where><if test="name != null">AND name LIKE #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>
2.4 缓存机制
- 一级缓存(SqlSession 级):默认启用,缓存同一个
SqlSession
内的查询结果。 - 二级缓存(Mapper 级):需手动配置,跨
SqlSession
共享缓存(如 Ehcache、Redis)。
<cache eviction="LRU" size="1024"/>
2.5 插件扩展
- 通过拦截器(Interceptor)扩展功能,如分页插件 PageHelper。
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class PageInterceptor implements Interceptor {// 拦截并修改 SQL 语句,添加分页逻辑
}
3. 与 Spring 集成
- 事务管理:通过
SqlSessionTemplate
或@Transactional
注解集成 Spring 事务。 - 依赖注入:Mapper 接口可被 Spring 容器管理,直接注入到 Service 层。
@Repository
public class UserDao {@Autowiredprivate SqlSessionTemplate sqlSessionTemplate;public User getUserById(Long id) {return sqlSessionTemplate.selectOne("com.example.mapper.UserMapper.getUserById", id);}
}
4. 优势与适用场景
- 优势:
- 灵活控制 SQL:适合需要优化复杂查询或利用数据库特有功能的场景。
- 解耦 SQL 与代码:通过 XML 或注解管理 SQL,便于维护。
- 轻量级:相比 Hibernate,学习曲线平缓,性能损耗低。
- 适用场景:
- 遗留系统迁移或数据库表结构复杂。
- 需要高频优化 SQL 的性能敏感型应用。
- 团队熟悉 SQL 但希望减少 JDBC 模板代码。
5. 总结:MyBatis 工作原理图
配置文件 (mybatis-config.xml + Mapper XML) | |
↓ | |
SqlSessionFactoryBuilder 解析配置 → 创建 SqlSessionFactory | |
↓ | |
SqlSessionFactory.openSession() → 获取 SqlSession(含 Executor) | |
↓ | |
SqlSession.getMapper(UserMapper.class) → 动态代理生成接口实现 | |
↓ | |
调用 Mapper 方法 → 解析 SQL → 执行 JDBC → 映射结果 → 返回 Java 对象 |
通过这种设计,MyBatis 在 灵活性与易用性 之间取得了平衡,成为 Java 生态中主流的持久层框架之一。