Mybatis DyanmicSqlSourcce

  • Author: HuiFer
  • 源码阅读工程: SourceHot-Mybatis

  • org.apache.ibatis.scripting.xmltags.DynamicSqlSource

  • org.apache.ibatis.scripting.xmltags.DynamicContext.DynamicContext
  1. <select id="list" resultType="com.huifer.mybatis.entity.HsSell">
  2. select * from hs_sell
  3. <trim prefix="WHERE" prefixOverrides="AND |OR">
  4. <if test="ID != null">
  5. and ID = #{ID,jdbcType=INTEGER}
  6. </if>
  7. </trim>
  8. </select>

image-20191219151247240

image-20191219151408597

  1. public class MixedSqlNode implements SqlNode {
  2. private final List<SqlNode> contents;
  3. public MixedSqlNode(List<SqlNode> contents) {
  4. this.contents = contents;
  5. }
  6. @Override
  7. public boolean apply(DynamicContext context) {
  8. // 调用 salNode 对象本身的 apply 方法解析 sql
  9. contents.forEach(node -> node.apply(context));
  10. return true;
  11. }
  12. }
  • 根据 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

  1. /**
  2. * @author Clinton Begin
  3. */
  4. public class StaticTextSqlNode implements SqlNode {
  5. private final String text;
  6. public StaticTextSqlNode(String text) {
  7. this.text = text;
  8. }
  9. /**
  10. * 静态文本apply 方法
  11. * @param context
  12. * @return
  13. */
  14. @Override
  15. public boolean apply(DynamicContext context) {
  16. context.appendSql(text);
  17. return true;
  18. }
  19. }
  • org.apache.ibatis.scripting.xmltags.DynamicContext#appendSql

    1. public void appendSql(String sql) {
    2. sqlBuilder.add(sql);
    3. }
  • 解析trim标签

image-20191219152502960

  • 在解析trim的时候会往下解析下级标签

    1. @Override
    2. public boolean apply(DynamicContext context) {
    3. FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
    4. // 解析下级标签的入口
    5. boolean result = contents.apply(filteredDynamicContext);
    6. filteredDynamicContext.applyAll();
    7. return result;
    8. }

image-20191219152655746

  1. @Override
  2. public boolean apply(DynamicContext context) {
  3. if (evaluator.evaluateBoolean(test, context.getBindings())) {
  4. contents.apply(context);
  5. return true;
  6. }
  7. return false;
  8. }
  • evaluator.evaluateBoolean(test, context.getBindings())方法
  1. /**
  2. * @param expression 判断语句,ID != null
  3. * @param parameterObject 参数列表
  4. * @return
  5. */
  6. public boolean evaluateBoolean(String expression, Object parameterObject) {
  7. Object value = OgnlCache.getValue(expression, parameterObject);
  8. if (value instanceof Boolean) {
  9. return (Boolean) value;
  10. }
  11. if (value instanceof Number) {
  12. return new BigDecimal(String.valueOf(value)).compareTo(BigDecimal.ZERO) != 0;
  13. }
  14. return value != null;
  15. }
  1. /**
  2. * 取值
  3. * @param expression 判断语句,ID=NULL
  4. * @param root 参数列表
  5. * @return
  6. */
  7. public static Object getValue(String expression, Object root) {
  8. try {
  9. Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);
  10. // 判断是否存在 expression 的判断内容 (判断ID是否存在)
  11. return Ognl.getValue(parseExpression(expression), context, root);
  12. } catch (OgnlException e) {
  13. throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
  14. }
  15. }

image-20191219153341466

存在返回true

执行完成就得到了一个 sql

image-20191219153553127

继续执行org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql方法

image-20191219155129772

  • 发送 sqlorg.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)

      1. @SuppressWarnings("unchecked")
      2. @Override
      3. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
      4. ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
      5. if (closed) {
      6. // 判断当前是否关闭
      7. throw new ExecutorException("Executor was closed.");
      8. }
      9. if (queryStack == 0 && ms.isFlushCacheRequired()) {
      10. // 查询堆栈==0 和 是否需要刷新缓存
      11. // 清理本地缓存
      12. clearLocalCache();
      13. }
      14. List<E> list;
      15. try {
      16. // 堆栈+1,防止重新清理缓存
      17. queryStack++;
      18. // 通过 缓存key 在本地缓存中获取
      19. list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      20. if (list != null) {
      21. // 通过缓存 key 查到后处理 localOutputParameterCache
      22. handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      23. } else {
      24. // 没有查询到从数据库查询
      25. list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      26. }
      27. } finally {
      28. // 堆栈-1
      29. queryStack--;
      30. }
      31. if (queryStack == 0) {
      32. for (DeferredLoad deferredLoad : deferredLoads) {
      33. deferredLoad.load();
      34. }
      35. // 清空线程安全队列(延迟队列)
      36. // issue #601
      37. deferredLoads.clear();
      38. if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      39. // STATEMENT 清空本地缓存
      40. // issue #482
      41. clearLocalCache();
      42. }
      43. }
      44. return list;
      45. }
      • org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

        1. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        2. List<E> list;
        3. localCache.putObject(key, EXECUTION_PLACEHOLDER);
        4. try {
        5. list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        6. } finally {
        7. localCache.removeObject(key);
        8. }
        9. localCache.putObject(key, list);
        10. if (ms.getStatementType() == StatementType.CALLABLE) {
        11. localOutputParameterCache.putObject(key, parameter);
        12. }
        13. return list;
        14. }
        • org.apache.ibatis.executor.BaseExecutor#doQuery
        • org.apache.ibatis.executor.SimpleExecutor#doQuery

image-20191219160832704

  1. private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  2. Statement stmt;
  3. // 数据库连接
  4. Connection connection = getConnection(statementLog);
  5. // stms 创建
  6. // org.apache.ibatis.executor.statement.BaseStatementHandler.prepare
  7. stmt = handler.prepare(connection, transaction.getTimeout());
  8. // 参数放入
  9. handler.parameterize(stmt);
  10. return stmt;
  11. }

image-20191219160908212

  • org.apache.ibatis.executor.statement.BaseStatementHandler#prepare
    • org.apache.ibatis.executor.statement.PreparedStatementHandler#instantiateStatement
  1. @Override
  2. public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
  3. ErrorContext.instance().sql(boundSql.getSql());
  4. Statement statement = null;
  5. try {
  6. statement = instantiateStatement(connection);
  7. setStatementTimeout(statement, transactionTimeout);
  8. setFetchSize(statement);
  9. return statement;
  10. } catch (SQLException e) {
  11. closeStatement(statement);
  12. throw e;
  13. } catch (Exception e) {
  14. closeStatement(statement);
  15. throw new ExecutorException("Error preparing statement. Cause: " + e, e);
  16. }
  17. }
  1. @Override
  2. protected Statement instantiateStatement(Connection connection) throws SQLException {
  3. String sql = boundSql.getSql();
  4. if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
  5. String[] keyColumnNames = mappedStatement.getKeyColumns();
  6. if (keyColumnNames == null) {
  7. return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
  8. } else {
  9. return connection.prepareStatement(sql, keyColumnNames);
  10. }
  11. } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
  12. return connection.prepareStatement(sql);
  13. } else {
  14. return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  15. }
  16. }
  • 这个方法都去了java.sql.Connection#prepareStatement(java.lang.String, java.lang.String[])

  • 接下来需要考虑的问题是如何将?换成我们的参数2

    image-20191219161555793

  • 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

这样就拿到了value的值

image-20191219162506920

准备工作就绪了发送就可以了

doQuery的工作完成了继续往下走

  1. @Override
  2. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  3. Statement stmt = null;
  4. try {
  5. Configuration configuration = ms.getConfiguration();
  6. StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  7. stmt = prepareStatement(handler, ms.getStatementLog());
  8. return handler.query(stmt, resultHandler);
  9. } finally {
  10. closeStatement(stmt);
  11. }
  12. }
  • 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-20191219163640968

image-20191219163957488

处理后结果如上

  1. /**
  2. * 处理查询结果
  3. * @param stmt
  4. * @return
  5. * @throws SQLException
  6. */
  7. @Override
  8. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  9. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  10. final List<Object> multipleResults = new ArrayList<>();
  11. int resultSetCount = 0;
  12. ResultSetWrapper rsw = getFirstResultSet(stmt);
  13. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  14. int resultMapCount = resultMaps.size();
  15. validateResultMapsCount(rsw, resultMapCount);
  16. while (rsw != null && resultMapCount > resultSetCount) {
  17. ResultMap resultMap = resultMaps.get(resultSetCount);
  18. handleResultSet(rsw, resultMap, multipleResults, null);
  19. rsw = getNextResultSet(stmt);
  20. cleanUpAfterHandlingResultSet();
  21. resultSetCount++;
  22. }
  23. String[] resultSets = mappedStatement.getResultSets();
  24. if (resultSets != null) {
  25. while (rsw != null && resultSetCount < resultSets.length) {
  26. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  27. if (parentMapping != null) {
  28. String nestedResultMapId = parentMapping.getNestedResultMapId();
  29. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  30. handleResultSet(rsw, resultMap, null, parentMapping);
  31. }
  32. rsw = getNextResultSet(stmt);
  33. cleanUpAfterHandlingResultSet();
  34. resultSetCount++;
  35. }
  36. }
  37. // 查询结果
  38. return collapseSingleResultList(multipleResults);
  39. }