MyBatis 核心组件剖析:架构、协作与源码解读

[复制链接]
发表于 2025-6-5 02:26:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
MyBatis 作为一款经典的恒久层框架,其计划精妙之处在于通过几个核心组件的协作,将 SQL 操作与 Java 对象优雅地结合起来。本文将深入剖析 MyBatis 的核心组件,包罗它们的作用、相互关系以及底层实现原理。
1.MyBatis 核心组件概览

MyBatis 的核心组件紧张包罗以下几个部分:

  • SqlSessionFactoryBuilder:负责从 XML 设置文件或 Java 代码中构建 SqlSessionFactory。
  • SqlSessionFactory:工厂模式的实现,负责创建 SqlSession 实例。
  • SqlSession:提供了执行 SQL 下令的方法,是应用与 MyBatis 之间的紧张编程接口。
  • Executor:SqlSession 内部使用 Executor 来执行 SQL 语句。
  • Mapper 接口与映射文件:界说 SQL 语句与 Java 方法的映射关系。
  • TypeHandler:负责 Java 类型与 JDBC 类型之间的转换。
  • ParameterHandler:处理 SQL 参数。
  • ResultSetHandler:处理 SQL 查询效果集。
这些组件相互协作,形成了 MyBatis 的核心架构。下面我们通过一个团体架构图来直观地了解它们之间的关系:
  1. +-------------------+     +-------------------+     +-------------------+
  2. |                   |     |                   |     |                   |
  3. |  SqlSessionFactory |<--->|     SqlSession    |<--->|      MapperProxy  |
  4. |                   |     |                   |     |                   |
  5. +-------------------+     +-------------------+     +-------------------+
  6.           ^                      |     ^                      ^
  7.           |                      |     |                      |
  8.           |                      v     |                      |
  9. +-------------------+     +-------------------+     +-------------------+
  10. |                   |     |                   |     |                   |
  11. |    Configuration  |     |     Executor      |     |   MapperRegistry  |
  12. |                   |     |                   |     |                   |
  13. +-------------------+     +-------------------+     +-------------------+
  14.           ^                      |     ^
  15.           |                      |     |
  16.           |                      v     |
  17. +-------------------+     +-------------------+
  18. |                   |     |                   |
  19. |   MappedStatement |     |    TypeHandler    |
  20. |                   |     |                   |
  21. +-------------------+     +-------------------+
复制代码
2.核心组件详解

1. SqlSessionFactoryBuilder

作用:SqlSessionFactoryBuilder 是 MyBatis 的入口点,负责剖析设置文件并构建 SqlSessionFactory 实例。
源码关键代码
  1. public class SqlSessionFactoryBuilder {
  2.     public SqlSessionFactory build(InputStream inputStream) {
  3.         return build(inputStream, null, null);
  4.     }
  5.    
  6.     public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
  7.         try {
  8.             // 解析 XML 配置文件
  9.             XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
  10.             // 构建 Configuration 对象
  11.             return build(parser.parse());
  12.         } catch (Exception e) {
  13.             throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  14.         } finally {
  15.             ErrorContext.instance().reset();
  16.             try {
  17.                 inputStream.close();
  18.             } catch (IOException e) {
  19.                 // Intentionally ignore. Prefer previous error.
  20.             }
  21.         }
  22.     }
  23.    
  24.     public SqlSessionFactory build(Configuration config) {
  25.         // 创建 DefaultSqlSessionFactory 实例
  26.         return new DefaultSqlSessionFactory(config);
  27.     }
  28. }
复制代码
使用示例
  1. InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
  2. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
复制代码
2. SqlSessionFactory

作用:SqlSessionFactory 是一个工厂接口,负责创建 SqlSession 实例。它是线程安全的,可以被多个线程共享。
核心方法


  • openSession():创建一个新的 SqlSession 实例。
  • openSession(boolean autoCommit):创建一个带有主动提交功能的 SqlSession。
  • openSession(ExecutorType execType):创建一个指定执行器类型的 SqlSession。
源码关键代码
  1. public interface SqlSessionFactory {
  2.     SqlSession openSession();
  3.     SqlSession openSession(boolean autoCommit);
  4.     SqlSession openSession(Connection connection);
  5.     SqlSession openSession(TransactionIsolationLevel level);
  6.     SqlSession openSession(ExecutorType execType);
  7.     // 其他重载方法...
  8. }
  9. public class DefaultSqlSessionFactory implements SqlSessionFactory {
  10.     private final Configuration configuration;
  11.    
  12.     public DefaultSqlSessionFactory(Configuration configuration) {
  13.         this.configuration = configuration;
  14.     }
  15.    
  16.     @Override
  17.     public SqlSession openSession() {
  18.         return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  19.     }
  20.    
  21.     private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  22.         Transaction tx = null;
  23.         try {
  24.             final Environment environment = configuration.getEnvironment();
  25.             final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
  26.             tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  27.             // 创建执行器
  28.             final Executor executor = configuration.newExecutor(tx, execType);
  29.             // 创建 DefaultSqlSession 实例
  30.             return new DefaultSqlSession(configuration, executor, autoCommit);
  31.         } catch (Exception e) {
  32.             closeTransaction(tx); // may have fetched a connection so lets call close()
  33.             throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  34.         } finally {
  35.             ErrorContext.instance().reset();
  36.         }
  37.     }
  38. }
复制代码
3. SqlSession

作用:SqlSession 是 MyBatis 的核心接口,提供了执行 SQL 下令的方法。它是线程不安全的,应该在方法内部使用,用完后实时关闭。
核心方法


  • selectOne(String statement, Object parameter):查询单个效果。
  • selectList(String statement, Object parameter):查询多个效果。
  • insert(String statement, Object parameter):插入数据。
  • update(String statement, Object parameter):更新数据。
  • delete(String statement, Object parameter):删除数据。
  • commit():提交事件。
  • rollback():回滚事件。
  • getMapper(Class<T> type):获取 Mapper 接口的代理对象。
源码关键代码
  1. public interface SqlSession extends Closeable {
  2.     <T> T selectOne(String statement);
  3.     <T> T selectOne(String statement, Object parameter);
  4.     <E> List<E> selectList(String statement);
  5.     <E> List<E> selectList(String statement, Object parameter);
  6.     int insert(String statement);
  7.     int insert(String statement, Object parameter);
  8.     int update(String statement);
  9.     int update(String statement, Object parameter);
  10.     int delete(String statement);
  11.     int delete(String statement, Object parameter);
  12.     void commit();
  13.     void commit(boolean force);
  14.     void rollback();
  15.     void rollback(boolean force);
  16.     <T> T getMapper(Class<T> type);
  17.     Configuration getConfiguration();
  18.     Connection getConnection();
  19. }
  20. public class DefaultSqlSession implements SqlSession {
  21.     private final Configuration configuration;
  22.     private final Executor executor;
  23.     private final boolean autoCommit;
  24.     private boolean dirty;
  25.    
  26.     public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
  27.         this.configuration = configuration;
  28.         this.executor = executor;
  29.         this.autoCommit = autoCommit;
  30.         this.dirty = false;
  31.     }
  32.    
  33.     @Override
  34.     public <T> T selectOne(String statement, Object parameter) {
  35.         // Popular vote was to return null on 0 results and throw exception on too many.
  36.         List<T> list = this.selectList(statement, parameter);
  37.         if (list.size() == 1) {
  38.             return list.get(0);
  39.         } else if (list.size() > 1) {
  40.             throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
  41.         } else {
  42.             return null;
  43.         }
  44.     }
  45.    
  46.     @Override
  47.     public int insert(String statement, Object parameter) {
  48.         return update(statement, parameter);
  49.     }
  50.    
  51.     @Override
  52.     public int update(String statement, Object parameter) {
  53.         try {
  54.             dirty = true;
  55.             // 通过执行器执行更新操作
  56.             MappedStatement ms = configuration.getMappedStatement(statement);
  57.             return executor.update(ms, wrapCollection(parameter));
  58.         } catch (Exception e) {
  59.             throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  60.         } finally {
  61.             ErrorContext.instance().reset();
  62.         }
  63.     }
  64.    
  65.     @Override
  66.     public <T> T getMapper(Class<T> type) {
  67.         // 通过 Configuration 获取 Mapper 代理
  68.         return configuration.getMapper(type, this);
  69.     }
  70. }
复制代码
4. Executor

作用:Executor 是 MyBatis 的执行器,负责 SQL 语句的执行和缓存的维护。
紧张实现类


  • SimpleExecutor:简朴执行器,每次执行都会创建新的预处理语句。
  • ReuseExecutor:可重用执行器,会重用预处理语句。
  • BatchExecutor:批处理执行器,用于批量操作。
  • CachingExecutor:缓存执行器,用于二级缓存的管理。
源码关键代码
  1. public interface Executor {
  2.     ResultHandler NO_RESULT_HANDLER = null;
  3.    
  4.     int update(MappedStatement ms, Object parameter) throws SQLException;
  5.    
  6.     <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
  7.    
  8.     <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
  9.    
  10.     List<BatchResult> flushStatements() throws SQLException;
  11.    
  12.     void commit(boolean required) throws SQLException;
  13.    
  14.     void rollback(boolean required) throws SQLException;
  15.    
  16.     CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
  17.    
  18.     boolean isCached(MappedStatement ms, CacheKey key);
  19.    
  20.     void clearLocalCache();
  21.    
  22.     void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
  23.    
  24.     Transaction getTransaction();
  25.    
  26.     void close(boolean forceRollback);
  27.    
  28.     boolean isClosed();
  29.    
  30.     void setExecutorWrapper(Executor executor);
  31. }
  32. public abstract class BaseExecutor implements Executor {
  33.     // 实现 Executor 接口的方法
  34.     // 包含事务管理、缓存管理等通用逻辑
  35. }
  36. public class SimpleExecutor extends BaseExecutor {
  37.     @Override
  38.     public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  39.         Statement stmt = null;
  40.         try {
  41.             Configuration configuration = ms.getConfiguration();
  42.             StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
  43.             // 准备语句
  44.             stmt = prepareStatement(handler, ms.getStatementLog());
  45.             // 执行更新
  46.             return handler.update(stmt);
  47.         } finally {
  48.             closeStatement(stmt);
  49.         }
  50.     }
  51.    
  52.     @Override
  53.     public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  54.         Statement stmt = null;
  55.         try {
  56.             Configuration configuration = ms.getConfiguration();
  57.             StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  58.             // 准备语句
  59.             stmt = prepareStatement(handler, ms.getStatementLog());
  60.             // 执行查询
  61.             return handler.query(stmt, resultHandler);
  62.         } finally {
  63.             closeStatement(stmt);
  64.         }
  65.     }
  66. }
复制代码
5. Mapper 接口与映射文件

作用:Mapper 接口界说了数据库操作的方法,映射文件(或注解)界说了这些方法对应的 SQL 语句。
映射文件示例
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3.   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4.   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.example.mapper.UserMapper">
  6.    
  7.     <select id="getUserById" parameterType="int" resultType="com.example.entity.User">
  8.         SELECT * FROM users WHERE id = #{id}
  9.     </select>
  10.    
  11.     <insert id="insertUser" parameterType="com.example.entity.User">
  12.         INSERT INTO users (username, email, age)
  13.         VALUES (#{username}, #{email}, #{age})
  14.     </insert>
  15.    
  16.     <!-- 其他 SQL 映射... -->
  17. </mapper>
复制代码
Mapper 接口示例
  1. package com.example.mapper;
  2. import com.example.entity.User;
  3. import java.util.List;
  4. public interface UserMapper {
  5.     User getUserById(int id);
  6.     void insertUser(User user);
  7.     void updateUser(User user);
  8.     void deleteUser(int id);
  9.     List<User> getAllUsers();
  10. }
复制代码
MapperProxy 实现
MyBatis 使用动态代理实现 Mapper 接口:
  1. public class MapperProxy<T> implements InvocationHandler, Serializable {
  2.     private static final long serialVersionUID = -642454039855972983L;
  3.     private final SqlSession sqlSession;
  4.     private final Class<T> mapperInterface;
  5.     private final Map<Method, MapperMethodInvoker> methodCache;
  6.    
  7.     public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
  8.         this.sqlSession = sqlSession;
  9.         this.mapperInterface = mapperInterface;
  10.         this.methodCache = methodCache;
  11.     }
  12.    
  13.     @Override
  14.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  15.         try {
  16.             if (Object.class.equals(method.getDeclaringClass())) {
  17.                 return method.invoke(this, args);
  18.             } else {
  19.                 return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
  20.             }
  21.         } catch (Throwable t) {
  22.             throw ExceptionUtil.unwrapThrowable(t);
  23.         }
  24.     }
  25.    
  26.     private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  27.         try {
  28.             return methodCache.computeIfAbsent(method, m -> {
  29.                 if (m.isDefault()) {
  30.                     try {
  31.                         if (privateLookupInMethod == null) {
  32.                             return new DefaultMethodInvoker(getMethodHandleJava8(method));
  33.                         } else {
  34.                             return new DefaultMethodInvoker(getMethodHandleJava9(method));
  35.                         }
  36.                     } catch (IllegalAccessException | InstantiationException | InvocationTargetException
  37.                              | NoSuchMethodException e) {
  38.                         throw new RuntimeException(e);
  39.                     }
  40.                 } else {
  41.                     // 创建 MapperMethod 实例
  42.                     return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  43.                 }
  44.             });
  45.         } catch (RuntimeException re) {
  46.             Throwable cause = re.getCause();
  47.             throw cause == null ? re : cause;
  48.         }
  49.     }
  50. }
复制代码
3.核心组件协作流程

下面通过一个查询操作的时序图,展示 MyBatis 核心组件的协作流程:
  1. Client                SqlSession        Executor    MappedStatement    JDBC
  2.   |                      |                |              |               |
  3.   |  getUserById(1)      |                |              |               |
  4.   |--------------------->|                |              |               |
  5.   |                      |  getMappedStatement("...") |               |
  6.   |                      |---------------------------->|               |
  7.   |                      |                |              |               |
  8.   |                      |  query(ms, 1)  |              |               |
  9.   |                      |-------------->|              |               |
  10.   |                      |                |  getBoundSql() |               |
  11.   |                      |                |------------->|               |
  12.   |                      |                |              |               |
  13.   |                      |                |  prepareStatement()          |
  14.   |                      |                |----------------------------->|
  15.   |                      |                |              |  Connection   |
  16.   |                      |                |              |<-------------|
  17.   |                      |                |              |               |
  18.   |                      |                |  executeQuery()              |
  19.   |                      |                |----------------------------->|
  20.   |                      |                |              |  ResultSet    |
  21.   |                      |                |<-------------|               |
  22.   |                      |                |              |               |
  23.   |                      |                |  handleResultSets()          |
  24.   |                      |                |<-------------|               |
  25.   |                      |<---------------|              |               |
  26.   |<---------------------|                |              |               |
复制代码
4.总结

通过深入剖析 MyBatis 的核心组件,我们可以看到其计划的精妙之处:

  • 工厂模式:SqlSessionFactoryBuilder 构建 SqlSessionFactory,SqlSessionFactory 创建 SqlSession。
  • 代理模式:MapperProxy 实现 Mapper 接口的动态代理,将方法调用转换为 SQL 执行。
  • 计谋模式:Executor 提供多种执行计谋(SimpleExecutor、ReuseExecutor、BatchExecutor)。
  • 模板方法模式:BaseExecutor 实现了通用的执行逻辑,具体实现由子类完成。
这种计划使得 MyBatis 既保持了机动性,又提供了简朴易用的 API。开辟者可以通过设置文件或注解界说 SQL 映射,然后通过 Mapper 接口进行数据库操作,无需编写繁琐的 JDBC 代码。
在实际开辟中,理解 MyBatis 的核心组件和工作原理,有助于我们更好地使用 MyBatis 进行开辟,也能够在遇到问题时更快地定位和办理问题。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5

GMT+8, 2025-7-4 04:51 , Processed in 0.254955 second(s), 34 queries 手机版|qidao123.com技术社区-IT企服评测▪应用市场 ( 浙ICP备20004199 )|网站地图

快速回复 返回顶部 返回列表