mybatis中BoundSql获取流程简单分析?

入口:MappedStatement#getBoundSql方法

public BoundSql getBoundSql(Object parameterObject) {
// 调用SqlSource获取BoundSql
   BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
   List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
   if (parameterMappings == null || parameterMappings.isEmpty()) {
     boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
   }

   // check for nested result maps in parameter mappings (issue #30)
   for (ParameterMapping pm : boundSql.getParameterMappings()) {
     String rmId = pm.getResultMapId();
     if (rmId != null) {
       ResultMap rm = configuration.getResultMap(rmId);
       if (rm != null) {
         hasNestedResultMaps |= rm.hasNestedResultMaps();
       }
     }
   }

   return boundSql;
 }
|--DynamicSqlSource#getBoundSql
@Override
public BoundSql getBoundSql(Object parameterObject) {
   DynamicContext context = new DynamicContext(configuration, parameterObject);
   // 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法
   // 此处会处理${},也会处理动态标签
   // 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中
   rootSqlNode.apply(context);
   // 创建SQL信息解析器
   SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
   // 获取入参类型
   Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
   // 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中
   SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
   // 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?)
   BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
   for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
   }
   return boundSql;
}
|--SqlSourceBuilder#parse :解析 SQL 语句中的 #{}, 并将对应的参数信息封装到
ParameterMapping 对象集合中,然后封装到 StaticSqlSource
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
   ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType,
         additionalParameters);
   // 创建分词解析器
   GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
   // 解析#{}
   String sql = parser.parse(originalSql);
   // 将解析之后的SQL信息,封装到StaticSqlSource对象中
   // SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中
   return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
|--ParameterMappingTokenHandler# 构造方法
public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType,
      Map<String, Object> additionalParameters) {
   super(configuration);
   this.parameterType = parameterType;
   this.metaParameters = configuration.newMetaObject(additionalParameters);
}
|--GenericTokenParser# 构造方法:指定待分析的 openToken closeToken ,并指定
处理器
public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
  this.openToken = openToken;
  this.closeToken = closeToken;
  this.handler = handler;
}
|--GenericTokenParser#parse :解析 SQL 语句,处理 openToken closeToken 中的
内容
/**
 * 解析${}和#{}
 * @param text
 * @return
 */
public String parse(String text) {
  if (text == null || text.isEmpty()) {
    return "";
  }
  // search open token
  int start = text.indexOf(openToken, 0);
  if (start == -1) {
    return text;
  }
  char[] src = text.toCharArray();
  int offset = 0;
  final StringBuilder builder = new StringBuilder();
  StringBuilder expression = null;
  while (start > -1) {
    if (start > 0 && src[start - 1] == '\\') {
      // this open token is escaped. remove the backslash and continue.
      builder.append(src, offset, start - offset - 1).append(openToken);
      offset = start + openToken.length();
    } else {
      // found open token. let's search close token.
      if (expression == null) {
        expression = new StringBuilder();
      } else {
        expression.setLength(0);
      }
      builder.append(src, offset, start - offset);
      offset = start + openToken.length();
      int end = text.indexOf(closeToken, offset);
      while (end > -1) {
        if (end > offset && src[end - 1] == '\\') {
          // this close token is escaped. remove the backslash and continue.
          expression.append(src, offset, end - offset - 1).append(closeToken);
          offset = end + closeToken.length();
          end = text.indexOf(closeToken, offset);
        } else {
          expression.append(src, offset, end - offset);
          offset = end + closeToken.length();
          break;
        }
      }
      if (end == -1) {
        // close token was not found.
        builder.append(src, start, src.length - start);
        offset = src.length;
      } else {
        builder.append(handler.handleToken(expression.toString()));
        offset = end + closeToken.length();
      }
    }
    start = text.indexOf(openToken, offset);
  }
  if (offset < src.length) {
    builder.append(src, offset, src.length - offset);
  }
  return builder.toString();
}
|--ParameterMappingTokenHandler#handleToken :处理 token #{}/${}
@Override
public String handleToken(String content) {
   parameterMappings.add(buildParameterMapping(content));
   return "?";
}
|--ParameterMappingTokenHandler#buildParameterMapping :创建
ParameterMapping 对象
private ParameterMapping buildParameterMapping(String content) {
   Map<String, String> propertiesMap = parseParameterMapping(content);
   String property = propertiesMap.get("property");
   Class<?> propertyType;
   if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
      propertyType = metaParameters.getGetterType(property);
   } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
      propertyType = parameterType;
   } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
      propertyType = java.sql.ResultSet.class;
   } else if (property == null || Map.class.isAssignableFrom(parameterType)) {
      propertyType = Object.class;
   } else {
      MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
      if (metaClass.hasGetter(property)) {
         propertyType = metaClass.getGetterType(property);
      } else {
         propertyType = Object.class;
      }
   }
   ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
   Class<?> javaType = propertyType;
   String typeHandlerAlias = null;
   for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
      String name = entry.getKey();
      String value = entry.getValue();
      if ("javaType".equals(name)) {
         javaType = resolveClass(value);
         builder.javaType(javaType);
      } else if ("jdbcType".equals(name)) {
         builder.jdbcType(resolveJdbcType(value));
      } else if ("mode".equals(name)) {
         builder.mode(resolveParameterMode(value));
      } else if ("numericScale".equals(name)) {
         builder.numericScale(Integer.valueOf(value));
      } else if ("resultMap".equals(name)) {
         builder.resultMapId(value);
      } else if ("typeHandler".equals(name)) {
         typeHandlerAlias = value;
      } else if ("jdbcTypeName".equals(name)) {
         builder.jdbcTypeName(value);
      } else if ("property".equals(name)) {
         // Do Nothing
      } else if ("expression".equals(name)) {
         throw new BuilderException("Expression based parameters are not supported yet");
      } else {
         throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content
               + "}.  Valid properties are " + parameterProperties);
      }
   }
   if (typeHandlerAlias != null) {
      builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
   }
   return builder.build();
}
|--StaticSqlSource# 构造方法:将解析之后的 SQL 信息,封装到 StaticSqlSource
public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) {
  this.sql = sql;
  this.parameterMappings = parameterMappings;
  this.configuration = configuration;
}
|--RawSqlSource#getBoundSql
@Override
public BoundSql getBoundSql(Object parameterObject) {
   return sqlSource.getBoundSql(parameterObject);
}
|--StaticSqlSource#getBoundSql
@Override
public BoundSql getBoundSql(Object parameterObject) {
  return new BoundSql(configuration, sql, parameterMappings, parameterObject);
}
|--BoundSql# 构造方法:将解析后的 sql 信息、参数映射信息、入参对象组合到
BoundSql 对象中
public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {
  this.sql = sql;
  this.parameterMappings = parameterMappings;
  this.parameterObject = parameterObject;
  this.additionalParameters = new HashMap<>();
  this.metaParameters = configuration.newMetaObject(additionalParameters);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值