
MyBatis 是一个流行的持久层框架,主要用于在 Java 应用程序中处理数据库交互。与传统的 JDBC 不同,MyBatis 提供了更高层次的抽象,通过映射文件或注解方式将 SQL 语句和 Java 对象关联起来,简化了数据库操作。MyBatis 不是一个全功能的 ORM(Object-Relational Mapping)框架,但它在保持 SQL 控制的同时,提供了方便的结果映射和参数处理功能。
一、MyBatis 的核心组件
MyBatis 的工作原理可以通过其核心组件来理解,这些组件包括:
- SqlSessionFactory:用于创建 SqlSession 实例的工厂。SqlSession 是 MyBatis 执行持久化操作的主要接口。
- SqlSession:MyBatis 的主要操作接口,通过它可以执行 SQL 语句、获取映射器(Mapper)实例、管理事务等。
- Mapper:映射器接口,用于定义数据库操作方法。MyBatis 通过动态代理技术,将 SQL 映射到这些接口的方法上。
- Configuration:配置类,保存 MyBatis 的配置信息,包括映射文件、数据源、环境设置等。
- MappedStatement:封装了一条 SQL 语句的所有信息,包括 SQL 字符串、输入参数、输出结果类型等。
- Executor:执行器,用于执行 SQL 语句并返回结果,是 MyBatis 的底层引擎。
- Cache:缓存组件,用于缓存查询结果,提升性能。
二、MyBatis 的初始化与配置加载
-
加载配置文件:MyBatis 初始化的第一步是加载配置文件(
mybatis-config.xml)。这个文件包含了 MyBatis 的全局配置,包括环境配置(如数据源、事务管理器)、别名设置、插件、缓存等配置。 -
构建 SqlSessionFactory:通过读取配置文件,MyBatis 会构建
SqlSessionFactory对象。SqlSessionFactory是一个重量级对象,通常在应用启动时创建一次,并在应用的整个生命周期中共享。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 解析映射文件:在配置文件中,还会指定映射文件的位置,这些映射文件(Mapper 文件)定义了 SQL 语句与 Java 对象之间的映射关系。MyBatis 在初始化时会解析这些映射文件,将其转换为
MappedStatement对象存储在Configuration中。
三、SqlSession 的工作原理
SqlSession 是 MyBatis 执行数据库操作的核心接口,通常由 SqlSessionFactory 创建。它提供了多种方法来执行 SQL 语句,例如 selectOne、selectList、insert、update、delete 等。SqlSession 的生命周期较短,通常在每次数据库操作时创建,操作完成后即关闭。
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
}
-
获取 Mapper 接口:通过
SqlSession.getMapper(Class<T> type)方法,MyBatis 会返回一个映射器接口的代理对象。这个代理对象负责将接口方法调用转发到具体的 SQL 执行逻辑上。 -
执行 SQL 语句:当调用
Mapper接口的方法时,代理对象会根据方法的签名找到对应的MappedStatement对象,构建 SQL 语句并执行。 -
管理事务:
SqlSession还负责事务的管理,开发者可以显式地调用commit或rollback方法,或者在自动提交模式下自动管理事务。 -
关闭资源:
SqlSession的使用遵循“打开-操作-关闭”的模式,使用完毕后,必须显式关闭以释放数据库连接等资源。
四、Mapper 的工作原理
MyBatis 通过 Mapper 接口来实现 SQL 的调用。Mapper 接口中的每个方法都对应一个 SQL 语句。MyBatis 使用动态代理模式在运行时生成 Mapper 接口的实现类,当调用接口方法时,MyBatis 会拦截该调用,并将其映射到相应的 SQL 语句。
public interface UserMapper {
User selectUserById(int id);
}
-
方法签名与 SQL 映射:
Mapper接口的方法通过方法签名(方法名和参数)与映射文件中的 SQL 语句关联。MyBatis 会根据方法名匹配映射文件中的id,找到对应的 SQL 语句进行执行。 -
参数绑定与结果映射:在执行 SQL 语句时,MyBatis 会自动绑定方法参数到 SQL 语句的参数占位符上,并根据结果映射(
ResultMap)将查询结果转换为相应的 Java 对象。
五、Executor 和 MappedStatement 的工作原理
-
MappedStatement:这是 MyBatis 中最重要的配置对象之一,它包含了 SQL 语句的所有信息,如 SQL 字符串、输入参数类型、输出结果类型、缓存配置等。当
Mapper方法被调用时,MyBatis 会从Configuration中获取对应的MappedStatement,然后通过Executor来执行这个语句。 -
Executor:
Executor是 MyBatis 执行 SQL 语句的核心组件。它负责与数据库通信,执行 SQL,并返回结果。Executor有多种实现,常见的有SimpleExecutor、ReuseExecutor和BatchExecutor。- SimpleExecutor:每次执行 SQL 语句时都会创建新的
Statement对象。 - ReuseExecutor:执行 SQL 语句时会复用
Statement对象,提高性能。 - BatchExecutor:支持批处理操作,将多条 SQL 语句批量执行,以减少数据库通信的次数。
- SimpleExecutor:每次执行 SQL 语句时都会创建新的
-
执行流程:
Executor首先会检查是否有缓存命中(一级缓存或二级缓存),如果缓存命中,则直接返回缓存结果。- 如果缓存未命中,
Executor会通过MappedStatement中的 SQL 语句和参数,构建真正的 SQL 语句,并通过 JDBC API 执行。 - 执行结果将被封装为相应的 Java 对象,并存储在缓存中(如果启用了缓存)。
六、缓存机制
MyBatis 提供了两级缓存机制,以提高查询性能:
-
一级缓存:
SqlSession级别的缓存。默认开启且无法禁用,它缓存了相同SqlSession下执行的相同 SQL 语句的查询结果。当一个SqlSession被关闭后,其一级缓存也被清空。 -
二级缓存:Mapper 级别的缓存。可以通过配置开启,二级缓存可以跨
SqlSession共享。MyBatis 的二级缓存可以使用多种实现(如 Ehcache、Redis 等),并且可以通过Cache接口进行自定义。
<cache/>
通过在映射文件中配置 <cache/> 标签,可以为该 Mapper 开启二级缓存。
七、动态 SQL
MyBatis 支持动态生成 SQL 语句,允许开发者根据不同的条件动态调整 SQL 的结构。动态 SQL 是 MyBatis 的一大特点,主要通过在 XML 映射文件中使用 <if>、<choose>、<where>、<set> 等标签来实现。
<select id="findActiveUsers" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email = #{email}
</if>
<if test="active == true">
AND active = 1
</if>
</where>
</select>
八、插件机制
MyBatis 提供了插件机制,允许开发者在 SQL 语句的执行过程中的各个环节进行拦截和增强。插件可以用于实现自定义的逻辑,如 SQL 语句的日志记录、性能监控、参数加密等。
插件通过实现 Interceptor 接口,并使用 @Intercepts 注解来定义拦截点。MyBatis 支持对 Executor、StatementHandler、ParameterHandler、ResultSetHandler 四个核心对象的拦截。
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class ExamplePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 在这里添加自定义逻辑
return invocation.proceed();
}
@Override
public Object plugin(Object
target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 设置插件的属性
}
}
九、总结
MyBatis 是一个功能强大的持久层框架,通过对 SQL 语句的精确控制和方便的映射配置,提供了一种灵活且高效的数据库访问方式。MyBatis 的工作原理主要围绕 SqlSessionFactory、SqlSession、Mapper、Executor、MappedStatement 这几个核心组件展开,通过配置文件和映射文件,将 Java 对象和数据库表有效地连接起来。
MyBatis 通过动态代理、缓存机制、动态 SQL、插件机制等特性,极大地提升了数据库操作的简洁性和可维护性,同时保留了对 SQL 语句的完全控制权,适合于各种需要精细化控制 SQL 的场景。理解 MyBatis 的工作原理,有助于开发者更好地使用这个工具,编写高效、可维护的持久层代码。
530



被折叠的 条评论
为什么被折叠?



