# Mybatis DyanmicSqlSourcce - Author: [HuiFer](https://github.com/huifer) - 源码阅读工程: [SourceHot-Mybatis](https://github.com/SourceHot/mybatis-read.git) - `org.apache.ibatis.scripting.xmltags.DynamicSqlSource` - `org.apache.ibatis.scripting.xmltags.DynamicContext.DynamicContext` ```XML ``` ![image-20191219151247240](/image/mybatis/image-20191219151247240.png) ![image-20191219151408597](/image/mybatis/image-20191219151408597.png) ```java public class MixedSqlNode implements SqlNode { private final List contents; public MixedSqlNode(List contents) { this.contents = contents; } @Override public boolean apply(DynamicContext context) { // 调用 salNode 对象本身的 apply 方法解析 sql contents.forEach(node -> node.apply(context)); return true; } } ``` - 根据mapper.xml文件中的代码流程 需要走 `org.apache.ibatis.scripting.xmltags.StaticTextSqlNode#apply` `org.apache.ibatis.scripting.xmltags.TrimSqlNode#apply` `org.apache.ibatis.scripting.xmltags.IfSqlNode#apply` ![image-20191219152254274](/image/mybatis/image-20191219152254274.png) ```java /** * @author Clinton Begin */ public class StaticTextSqlNode implements SqlNode { private final String text; public StaticTextSqlNode(String text) { this.text = text; } /** * 静态文本apply 方法 * @param context * @return */ @Override public boolean apply(DynamicContext context) { context.appendSql(text); return true; } } ``` - `org.apache.ibatis.scripting.xmltags.DynamicContext#appendSql` ```JAVA public void appendSql(String sql) { sqlBuilder.add(sql); } ``` - 解析`trim`标签 ![image-20191219152502960](/image/mybatis/image-20191219152502960.png) - 在解析`trim`的时候会往下解析下级标签 ```java @Override public boolean apply(DynamicContext context) { FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context); // 解析下级标签的入口 boolean result = contents.apply(filteredDynamicContext); filteredDynamicContext.applyAll(); return result; } ``` ![image-20191219152655746](/image/mybatis/image-20191219152655746.png) ```JAVA @Override public boolean apply(DynamicContext context) { if (evaluator.evaluateBoolean(test, context.getBindings())) { contents.apply(context); return true; } return false; } ``` - `evaluator.evaluateBoolean(test, context.getBindings())`方法 ```JAVA /** * @param expression 判断语句,ID != null * @param parameterObject 参数列表 * @return */ public boolean evaluateBoolean(String expression, Object parameterObject) { Object value = OgnlCache.getValue(expression, parameterObject); if (value instanceof Boolean) { return (Boolean) value; } if (value instanceof Number) { return new BigDecimal(String.valueOf(value)).compareTo(BigDecimal.ZERO) != 0; } return value != null; } ``` ```JAVA /** * 取值 * @param expression 判断语句,ID=NULL * @param root 参数列表 * @return */ public static Object getValue(String expression, Object root) { try { Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null); // 判断是否存在 expression 的判断内容 (判断ID是否存在) return Ognl.getValue(parseExpression(expression), context, root); } catch (OgnlException e) { throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e); } } ``` ![image-20191219153341466](/image/mybatis/image-20191219153341466.png) 存在返回`true` 执行完成就得到了一个sql ![image-20191219153553127](/image/mybatis/image-20191219153553127.png) 继续执行`org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql`方法 ![image-20191219155129772](/image/mybatis/image-20191219155129772.png) - 发送sql`org.apache.ibatis.executor.SimpleExecutor#doQuery` - 调用链路如下 - `org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)` - `org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)` - `org.apache.ibatis.executor.Executor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)` - `org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)` ```java @SuppressWarnings("unchecked") @Override public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { // 判断当前是否关闭 throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { // 查询堆栈==0 和 是否需要刷新缓存 // 清理本地缓存 clearLocalCache(); } List list; try { // 堆栈+1,防止重新清理缓存 queryStack++; // 通过 缓存key 在本地缓存中获取 list = resultHandler == null ? (List) localCache.getObject(key) : null; if (list != null) { // 通过缓存 key 查到后处理 localOutputParameterCache handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 没有查询到从数据库查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { // 堆栈-1 queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // 清空线程安全队列(延迟队列) // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // STATEMENT 清空本地缓存 // issue #482 clearLocalCache(); } } return list; } ``` - `org.apache.ibatis.executor.BaseExecutor#queryFromDatabase` ```java private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; } ``` - `org.apache.ibatis.executor.BaseExecutor#doQuery` - `org.apache.ibatis.executor.SimpleExecutor#doQuery` ![image-20191219160832704](/image/mybatis/image-20191219160832704.png) ```java private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; // 数据库连接 Connection connection = getConnection(statementLog); // stms 创建 // org.apache.ibatis.executor.statement.BaseStatementHandler.prepare stmt = handler.prepare(connection, transaction.getTimeout()); // 参数放入 handler.parameterize(stmt); return stmt; } ``` ![image-20191219160908212](/image/mybatis/image-20191219160908212.png) - `org.apache.ibatis.executor.statement.BaseStatementHandler#prepare` - `org.apache.ibatis.executor.statement.PreparedStatementHandler#instantiateStatement` ```java @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); } } ``` ```java @Override protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareStatement(sql); } else { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } ``` - 这个方法都去了`java.sql.Connection#prepareStatement(java.lang.String, java.lang.String[])` - 接下来需要考虑的问题是如何将`?`换成我们的参数`2` ![image-20191219161555793](/image/mybatis/image-20191219161555793.png) - `org.apache.ibatis.executor.statement.StatementHandler#parameterize` - `org.apache.ibatis.executor.statement.RoutingStatementHandler#parameterize` - `org.apache.ibatis.executor.statement.StatementHandler#parameterize` - `org.apache.ibatis.executor.statement.PreparedStatementHandler#parameterize` - `org.apache.ibatis.executor.parameter.ParameterHandler` - `org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters` ![image-20191219162258040](/image/mybatis/image-20191219162258040.png) 这样就拿到了`value`的值 ![image-20191219162506920](/image/mybatis/image-20191219162506920.png) 准备工作就绪了发送就可以了 `doQuery`的工作完成了继续往下走 ```java @Override public List 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); } } ``` - `org.apache.ibatis.executor.statement.RoutingStatementHandler#query` - `org.apache.ibatis.executor.statement.PreparedStatementHandler#query` - `org.apache.ibatis.executor.resultset.ResultSetHandler#handleResultSets` - `org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets` ![image-20191219163628214](/image/mybatis/image-20191219163628214.png) ![image-20191219163640968](/image/mybatis/image-20191219163640968.png) ![image-20191219163957488](/image/mybatis/image-20191219163957488.png) 处理后结果如上 ```java /** * 处理查询结果 * @param stmt * @return * @throws SQLException */ @Override public List handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List multipleResults = new ArrayList<>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt); List resultMaps = mappedStatement.getResultMaps(); 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.getResultSets(); 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); } ```