Mapper 通过类名和方法名就可以匹配到配置的SQL。
Mapper 执行的过程是通过 Executor,StatementHandler,ParameterHandler 和 ResultHandler 来完成数据库操作和结果返回的。
四大对象
- Executor 代表执行器,由它来调度 
StatementHandler,ParameterHandler 和 ResultHandler 等来执行对应的 SQL。 
- StatementHandler 数据库会话器,作用是使用数据库的 **Statement(PreparedStatement)**执行操作,它是四大对象的核心,起到承上启下的作用。
 
- ParameterHandler 用于 SQL 对参数的处理。
 
- ResultHandler 是进行最后数据集(ResultSet)的封装返回处理的。
 
这四大对象的都是在 Configuration 类中创建的,从这可以看出 Configuration 类是 MyBatis 的核心。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
   | public class Configuration {                     	public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,       BoundSql boundSql) {     ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,         parameterObject, boundSql);     return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);   }
       public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,       ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {     ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,         resultHandler, boundSql, rowBounds);     return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);   }
       public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,       Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {     StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,         rowBounds, resultHandler, boundSql);     return (StatementHandler) interceptorChain.pluginAll(statementHandler);   }
       public Executor newExecutor(Transaction transaction) {     return newExecutor(transaction, defaultExecutorType);   }
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {     executorType = executorType == null ? defaultExecutorType : executorType;     Executor executor;     if (ExecutorType.BATCH == executorType) {       executor = new BatchExecutor(this, transaction);     } else if (ExecutorType.REUSE == executorType) {       executor = new ReuseExecutor(this, transaction);     } else {       executor = new SimpleExecutor(this, transaction);     }     if (cacheEnabled) {       executor = new CachingExecutor(executor);     }     return (Executor) interceptorChain.pluginAll(executor);   }
  | 
 
执行器
执行器(Executor)是一个真正执行 Java 和 数据库交互的东西,起到至关重要的作用。
在 MyBatis 中存在三种执行器,默认在 MyBatis 的 Configuration 类中创建执行器对象,配置文件 setting 元素的属性是 defaultExecutorType。
- SIMPLE,简易执行器,默认的执行器。
 
- REUSE,是一种执行器重用预处理语句。
 
- BATCH,执行器重要语句和批量更新,它是针对批量专用的执行器。
 
创建执行器 Executor 源码逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | public Executor newExecutor(Transaction transaction, ExecutorType executorType) {   executorType = executorType == null ? defaultExecutorType : executorType;   Executor executor;   if (ExecutorType.BATCH == executorType) {     executor = new BatchExecutor(this, transaction);   } else if (ExecutorType.REUSE == executorType) {     executor = new ReuseExecutor(this, transaction);   } else {     executor = new SimpleExecutor(this, transaction);   }   if (cacheEnabled) {     executor = new CachingExecutor(executor);   }   return (Executor) interceptorChain.pluginAll(executor); }
  | 
 
配置文件 setting 属性配置:
1 2 3 4 5 6 7
   | <settings>     <setting name="defaultExecutorType" value="SIMPLE"/> </settings>
  <settings>     <setting name="defaultExecutorType" value="BATCH"/> </settings>
   | 
 
MyBatis 会根据配置的类型去确定需要创建三种执行器中的哪一种,在创建对象后,会执行下面这样一行代码。
1
   | interceptorChain.pluginAll(executor);
   | 
 
这就是 MyBatis 的插件,这里它将为我们构建一层层的动态代理对象。在调度真实的 Executor 方法之前执行配置插件的代码可以修改。
以SIMPLE执行器为例,看看执行器方法内部。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   |   @Override   public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,       BoundSql boundSql) throws SQLException {     Statement stmt = null;     try {       Configuration configuration = ms.getConfiguration();       StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler,           boundSql);                stmt = prepareStatement(handler, ms.getStatementLog());       return handler.query(stmt, resultHandler);     } finally {       closeStatement(stmt);     }   }
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {     Statement stmt;     Connection connection = getConnection(statementLog);     stmt = handler.prepare(connection, transaction.getTimeout());     handler.parameterize(stmt);     return stmt;   } }
   | 
 
MyBatis 根据 Configuration 来构建 StatementHandler,然后使用 PreparedStatement 方法对 SQL 编译并对参数进行初始化。实现过程是它调用了 StatementHandler 的 prepare() 方法进行预编译和基础设置,然后通过 StatementHandler 的 parameterize() 来设置参数并执行,ResultHandler 再组装查询结果返回给调用方来完成一次查询。
数据库会话器
数据库会话器(StatementHandler)是专门处理数据库会话的。下面看看 MyBatis 如何创建 StatementHandler 的。
在 Configuration 类里创建 StatementHandler,很显然,创建的真实对象是 RoutingStatementHandler 对象,它实现了接口 StatementHandler,和 Executor 一样,用代理对象做一层层的封装。。
1 2 3 4 5 6 7 8
   | public class Configuration { 	public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,       Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {     StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,         rowBounds, resultHandler, boundSql);     return (StatementHandler) interceptorChain.pluginAll(statementHandler);   } }
  | 
 
在初始化 RoutingStatementHandler 对象的时候它会根据上下文环境决定创建哪个 StatementHandler 对象。
RoutingStatementHandler 不是我们真实的服务对象,它是通过适配模式找到应的的 StatementHandler 来执行的。
StatementHandler  和 Executor 一样分为三种:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
   | public class RoutingStatementHandler implements StatementHandler {
       private final StatementHandler delegate;
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,       ResultHandler resultHandler, BoundSql boundSql) {
      switch (ms.getStatementType()) {       case STATEMENT:         delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);         break;       case PREPARED:         delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);         break;       case CALLABLE:         delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);         break;       default:         throw new ExecutorException("Unknown statement type: " + ms.getStatementType());     }
    }
    @Override   public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {     return delegate.prepare(connection, transactionTimeout);   }
    @Override   public void parameterize(Statement statement) throws SQLException {     delegate.parameterize(statement);   }
    @Override   public void batch(Statement statement) throws SQLException {     delegate.batch(statement);   }
    @Override   public int update(Statement statement) throws SQLException {     return delegate.update(statement);   }
    @Override   public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {     return delegate.query(statement, resultHandler);   }
    @Override   public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {     return delegate.queryCursor(statement);   }
    @Override   public BoundSql getBoundSql() {     return delegate.getBoundSql();   }
    @Override   public ParameterHandler getParameterHandler() {     return delegate.getParameterHandler();   } }
 
  | 
 
数据会话器定义了一个对象的适配器 delegate,它是一个 StatementHandler 接口对象,构造方法根据配置来适配对应的 StatementHandler 对象。它的作用是给实现类对象的使用提供一个统一,简易的使用适配器。此为对象的适配模式,可以让我们使用现有的类和方法对象提供服务,也可以根据实际需求对象屏蔽一些方法,甚至加入新的服务。
以最常用的 PreparedStatementHandler 为例,看看 MyBatis 早怎么执行查询的。看看它的主要三个方法 prepare、parameterize、query 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | public abstract class BaseStatementHandler implements StatementHandler {
    @Override   public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {     ErrorContext.instance().sql(boundSql.getSql());     Statement statement = null;     try {       statement = instantiateStatement(connection);       setStatementTimeout(statement, transactionTimeout);       setFetchSize(statement);       return statement;     } catch (SQLException e) {       closeStatement(statement);       throw e;     } catch (Exception e) {       closeStatement(statement);       throw new ExecutorException("Error preparing statement.  Cause: " + e, e);     }   }      }
  | 
 
prepare: instantiateStatement 方法是对 SQL 进行预编译。还做了一些基础配置,如设置超时、获最的最大行数等。然后 Executor 调用 parameterize 方法去设置参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | public class PreparedStatementHandler extends BaseStatementHandler {
    @Override   public void parameterize(Statement statement) throws SQLException {     parameterHandler.setParameters((PreparedStatement) statement);   }        @Override   public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {     PreparedStatement ps = (PreparedStatement) statement;     ps.execute();     return resultSetHandler.handleResultSets(ps);   }      }
  | 
 
在执行 query 方法前,参数和SQL已经被 prepare 预编译了,参数已经在 parameterize 方法设置了,接下来只是执行 SQL,然后返回结果就可以了。结果可以看到使用了 ResultHandler 进行封装和返回。
一条查询SQL执行过程:
- Executor 先调用 StatementHandler 的 prepare  方法预编译,同时设置一些基本运行的参数。
 
- 然后调用 parameterize  方法设置参数,完成预编译。
 
- 跟着就是执行查询,update() 也是这样,最后如果需要结果,就用 ResultSetHandler 封装结果返回给调用者。
 
参数处理器
MyBatis 通过参数处理器 ParameterHandler 对预编译语句进行参数设置,作用很明显,就是完成对预编译参数的设置。
1 2 3 4 5 6 7
   | public interface ParameterHandler {
    Object getParameterObject();
    void setParameters(PreparedStatement ps) throws SQLException;
  }
  | 
 
ParameterHandler 是个接口,提供了两个方法给重写,其中 getParameterObject() 方法的作用是返回参数对象,**setParameters()**作用是设置预编译 SQL 语句的参数。
MyBatis 为 ParameterHandler 提供了一个默认实现类 DefaultParameterHandler,看看其中 setParameters() 的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
   |  public class DefaultParameterHandler implements ParameterHandler {
    @Override   public void setParameters(PreparedStatement ps) {     ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();     if (parameterMappings != null) {       for (int i = 0; i < parameterMappings.size(); i++) {         ParameterMapping parameterMapping = parameterMappings.get(i);         if (parameterMapping.getMode() != ParameterMode.OUT) {           Object value;           String propertyName = parameterMapping.getProperty();           if (boundSql.hasAdditionalParameter(propertyName)) {              value = boundSql.getAdditionalParameter(propertyName);           } else if (parameterObject == null) {             value = null;           } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {             value = parameterObject;           } else {             MetaObject metaObject = configuration.newMetaObject(parameterObject);             value = metaObject.getValue(propertyName);           }           TypeHandler typeHandler = parameterMapping.getTypeHandler();           JdbcType jdbcType = parameterMapping.getJdbcType();           if (value == null && jdbcType == null) {             jdbcType = configuration.getJdbcTypeForNull();           }           try {             typeHandler.setParameter(ps, i + 1, value, jdbcType);           } catch (TypeException | SQLException e) {             throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);           }         }       }     }   }
  }
 
 
  | 
 
从代码中可以看到它是从 parameterObject 对象中取参数,然后使用 typeHandler 进行参数处理,如果有显式设置,则会根据签名注册的 typeHandler 对参数进行处理。而 typeHandler  也是在 MyBatis 初始化的时候,注册在 Configuration 里面的,需要的时候可以直接拿来用。这样就完成了参数设置。
结果处理器
结果处理器 ResultSetHandler 是对结果集进行封装返回。
ResultSetHandler接口:
1 2 3 4 5 6 7 8 9
   | public interface ResultSetHandler {
    <E> List<E> handleResultSets(Statement stmt) throws SQLException;
    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
    void handleOutputParameters(CallableStatement cs) throws SQLException;
  }
  | 
 
- handleResultSets:包装结果集。
 
- handleCursorResultSets:数据库内处理游标结果集。
 
- handleOutputParameters:处理存储过程输出参数。
 
MyBatis 同样提供了 ResultSetHandler 默认的实现类 DefaultResultSetHandler,默认情况下都是通过这个类进行处理。这个实现比较复杂,它涉及使用了 JAVASSIST 或者 CGLIB 作为延迟加载,然后通过 typeHandler 和 ObjectFactory 进行组装结果返回,而我们使用它时几乎不会需要改变它。