一、Executor(接口)
/** * 执行器 * */ public interface Executor { //不需要ResultHandler ResultHandler NO_RESULT_HANDLER = null; //更新 int update(MappedStatement ms, Object parameter) throws SQLException; //查询,带分页,带缓存,BoundSql <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; //查询,带分页 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; //刷新批处理语句 List<BatchResult> flushStatements() throws SQLException; //提交和回滚,参数是否要强制 void commit(boolean required) throws SQLException; void rollback(boolean required) throws SQLException; //创建CacheKey CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); //判断是否缓存了 boolean isCached(MappedStatement ms, CacheKey key); //清理Session缓存 void clearLocalCache(); //延迟加载 void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType); Transaction getTransaction(); void close(boolean forceRollback); boolean isClosed(); void setExecutorWrapper(Executor executor); }
//默认为简单执行器 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;//枚举类,下面提供源码
public Executor newExecutor(Transaction transaction) { return newExecutor(transaction, defaultExecutorType); } //产生执行器 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; //这句再做一下保护,防止粗心大意的人将defaultExecutorType设成null? executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; //然后就是简单的3个分支,产生3种执行器BatchExecutor/ReuseExecutor/SimpleExecutor 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); } //如果要求缓存,生成另一种CachingExecutor(默认就是有缓存),装饰者模式,所以默认都是返回CachingExecutor if (cacheEnabled) { executor = new CachingExecutor(executor); } //此处调用插件,通过插件可以改变Executor行为 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
/** * 执行器的类型 * */ public enum ExecutorType { //ExecutorType.SIMPLE //这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。 //ExecutorType.REUSE //这个执行器类型会复用预处理语句。 //ExecutorType.BATCH //这个执行器会批量执行所有更新语句,如果SELECT在它们中间执行还会标定它们是必须的,来保证一个简单并易于理解的行为。 SIMPLE, REUSE, BATCH }
如代码注释所说,拦截Executor。构建一层层动态代理对象,我们可以修改在执行真正的Executor方法之前来配置插件的代码,这就是插件的原理。再看看执行Executor的方法,其中有多个类,我们了解一下简单执行器SimpleExecutor的方法:
public class SimpleExecutor extends BaseExecutor { public SimpleExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } //update @Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); //新建一个StatementHandler //这里看到ResultHandler传入的是null StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); //准备语句 stmt = prepareStatement(handler, ms.getStatementLog()); //StatementHandler.update return handler.update(stmt); } finally { closeStatement(stmt); } } //select @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 //这里看到ResultHandler传入了 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); //准备语句 stmt = prepareStatement(handler, ms.getStatementLog()); //StatementHandler.query return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } } @Override public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { //doFlushStatements只是给batch用的,所以这里返回空 return Collections.emptyList(); } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); //调用StatementHandler.prepare stmt = handler.prepare(connection); //调用StatementHandler.parameterize handler.parameterize(stmt); return stmt; } }
//创建语句处理器 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); //插件在这里插入 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
其他的执行器与简单执行器的走法基本差不多,不多赘述,提供相关源码参考(可跳过下面源码部分了解下一个内容StatementHandler):
public class ReuseExecutor extends BaseExecutor { //可重用的执行器内部用了一个map,用来缓存SQL语句对应的Statement private final Map<String, Statement> statementMap = new HashMap<String, Statement>(); public ReuseExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } @Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Configuration configuration = ms.getConfiguration(); //和SimpleExecutor一样,新建一个StatementHandler //这里看到ResultHandler传入的是null StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); //准备语句 Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.update(stmt); } @Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } @Override public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { for (Statement stmt : statementMap.values()) { closeStatement(stmt); } statementMap.clear(); return Collections.emptyList(); } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; //得到绑定的SQL语句 BoundSql boundSql = handler.getBoundSql(); String sql = boundSql.getSql(); //如果缓存中已经有了,直接得到Statement if (hasStatementFor(sql)) { stmt = getStatement(sql); } else { //如果缓存没有找到,则和SimpleExecutor处理完全一样,然后加入缓存 Connection connection = getConnection(statementLog); stmt = handler.prepare(connection); putStatement(sql, stmt); } handler.parameterize(stmt); return stmt; } private boolean hasStatementFor(String sql) { try { return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed(); } catch (SQLException e) { return false; } } private Statement getStatement(String s) { return statementMap.get(s); } private void putStatement(String sql, Statement stmt) { statementMap.put(sql, stmt); } }二、StatementHandler(接口)
注意:新的Jar包中prepare中新增一个参数Integer):
StatementHandler有一个抽象实现类BaseStatementHandler和一个实现类RoutingStatementHandler,BaseStatementHandler有三个子类:
在Configuration中生成StatementHandler就三句代码,创建的实际对象为RoutingStatementHandler对象,它也是与Executor一样的,都是用代理对象来封装的。
观察RoutingStatementHandler就会发现其中的巧妙之处:
通过配置来选择具体的StatementHandler对象,我们来查看常用的PreparedStatementHandler(预处理语句处理器),由于其父类已经将prepare方法实现了:
父类BaseStatementHandler
@Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { //实例化Statement statement = instantiateStatement(connection);//对SQL进行预编译等操作 //设置超时 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); } } //如何实例化Statement,交给子类做 protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
设置参数是通过ParameterHandler处理的。接下来开始看下一个对象----ParameterHandler。
三、ParameterHandler:
它是对预编译语句进行参数的设置,完成对预编译参数的设置。
/** * 参数处理器 * */ public interface ParameterHandler { //得到参数 Object getParameterObject(); //设置参数 void setParameters(PreparedStatement ps) throws SQLException; }
它仅有一个默认的实现类:DefaultParameterHandler
** * 默认参数处理器 * */ public class DefaultParameterHandler implements ParameterHandler { private final TypeHandlerRegistry typeHandlerRegistry; private final MappedStatement mappedStatement; private final Object parameterObject; private BoundSql boundSql; private Configuration configuration; public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { this.mappedStatement = mappedStatement; this.configuration = mappedStatement.getConfiguration(); this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry(); this.parameterObject = parameterObject; this.boundSql = boundSql; } @Override public Object getParameterObject() { return parameterObject; } //设置参数 @Override public void setParameters(PreparedStatement ps) throws SQLException { 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) { //如果不是OUT,才设进去 Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params //若有额外的参数, 设为额外的参数 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { //若参数为null,直接设null value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { //若参数有相应的TypeHandler,直接设object value = parameterObject; } else { //除此以外,MetaObject.getValue反射取得值设进去 MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { //不同类型的set方法不同,所以委派给子类的setParameter方法 jdbcType = configuration.getJdbcTypeForNull(); } typeHandler.setParameter(ps, i + 1, value, jdbcType); } } } } }
把取到的参数(parameterObject)转换后(typeHandler),注册到Configuration中(typeHandler也是在其中配置好的)。
四、ResultSetHandler
/** * 结果集处理器 * */ public interface ResultSetHandler { //处理结果集 <E> List<E> handleResultSets(Statement stmt) throws SQLException; //处理OUT参数 void handleOutputParameters(CallableStatement cs) throws SQLException; }
mybatis已经为我们提供了一个默认实现类:DefaultResultSetHandler
由于其源码内容较多,节选部分参考:
@Override public void handleOutputParameters(CallableStatement cs) throws SQLException { final Object parameterObject = parameterHandler.getParameterObject(); final MetaObject metaParam = configuration.newMetaObject(parameterObject); final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); //循环处理每个参数 for (int i = 0; i < parameterMappings.size(); i++) { final ParameterMapping parameterMapping = parameterMappings.get(i); //只处理OUT|INOUT if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (ResultSet.class.equals(parameterMapping.getJavaType())) { //如果是ResultSet型(游标) //#{result, jdbcType=CURSOR, mode=OUT, javaType=ResultSet, resultMap=userResultMap} //先用CallableStatement.getObject取得这个游标,作为参数传进去 handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam); } else { //否则是普通型,核心就是CallableStatement.getXXX取得值 final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler(); metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); } } } }
@Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<Object>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); //一般resultMaps里只有一个元素 int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } String[] resultSets = mappedStatement.getResulSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } return collapseSingleResultList(multipleResults); }
由于实际操作中对它的改变几率低,不再讨论。
总结