Mybatis-SqlSource源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

SqlSource

作用于XMLLanguageDriver

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

/**
 * Represents the content of a mapped statement read from an XML file or an annotation.
 * It creates the SQL that will be passed to the database out of the input parameter received from the user.
 * 

* 构建动态SQL *

*

* 代表的内容映射语句读取XML文件或一个注解它创建的SQL将被传递到数据库收到用户的输入参数 *

*

* 参考博客:https://blog.csdn.net/LHQJ1992/article/details/90320639 *

* @author Clinton Begin */ public interface SqlSource { /** * 根据 {@code parameterObject} 构建动态SQL * @param parameterObject 参数对象 * @return {@link BoundSql} 对象 */ BoundSql getBoundSql(Object parameterObject); }

DynamicSqlSource

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.scripting.xmltags;

import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;

/**
 * 只创建DynamicSqlSource对象。完整可执行的sql,需要在调用getBoundSql(Parameter)方法时才能组装完成。
 * @author Clinton Begin
 */
public class DynamicSqlSource implements SqlSource {

  /**
   * mybatis配置信息
   */
  private final Configuration configuration;
  /**
   * DML标签下的子节点,封装成了MixedSqlNode
   */
  private final SqlNode rootSqlNode;

  /**
   *
   * @param configuration mybatis配置信息
   * @param rootSqlNode DML标签下的子节点,封装成了MixedSqlNode
   */
  public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
    this.configuration = configuration;
    this.rootSqlNode = rootSqlNode;
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    /**
     * 构建动态SQL上下文,DynamicContext主要用于记录解析动态SQL语句之后产生的SQL语句片段,
     * 可以认为它是一个用于记录动态SQL语句解析结果的容器
     */
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    //解析 SQL 片段,并将解析结果存储到 DynamicContext 中
    rootSqlNode.apply(context);
    // 解析 SQL 语句,并构建 StaticSqlSource,在此过程中将 sql 语句中的占位符 #{} 替换为问号 ?,并为每个占位符构建相应的 ParameterMapping
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    // 从SqlNode 上下文中得到完成的originalSql后开始构建SqlSource
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    //调用 StaticSqlSource 的 getBoundSql 获取 BoundSql
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    //将 DynamicContext 的 ContextMap 中的内容拷贝到 BoundSql 中
    context.getBindings().forEach(boundSql::setAdditionalParameter);
    return boundSql;
  }

}

ProviderSqlSource

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.builder.annotation;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;

import org.apache.ibatis.annotations.Lang;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.reflection.ParamNameResolver;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;

/**
 * SQL提供者的SQL源
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class ProviderSqlSource implements SqlSource {

  /**
   * Mybatis全局配置信息
   */
  private final Configuration configuration;
  /**
   * SQL脚本提供者类
   */
  private final Class providerType;
  /**
   * 语言驱动
   */
  private final LanguageDriver languageDriver;
  /**
   * SQL provider 的对应映射器方法的方法对象
   */
  private Method providerMethod;
  /**
   * SQL provider 的对应映射器方法的方法对象的SQL脚本参数名数组
   */
  private String[] providerMethodArgumentNames;
  /**
   * SQL provider 的对应映射器方法的方法对象的参数类型数组
   */
  private Class[] providerMethodParameterTypes;
  /**
   *  Sql provider 方法的上下文对象,封装着映射接口类,映射接口类方法对象, 数据库ID
   *  

* 在 SQL provider 的对应映射器方法的方法对象中有这个ProvideContext的参数类型时,才不会为null *

*/ private ProviderContext providerContext; /** * SQL provider 的对应映射器方法的方法对象的ProvideContext类型参数的索引位置 *

* 在 SQL provider 的对应映射器方法的方法对象中有这个ProvideContext的参数类型时,才不会为null *

*/ private Integer providerContextIndex; /** * @deprecated Please use the {@link #ProviderSqlSource(Configuration, Object, Class, Method)} instead of this. */ @Deprecated public ProviderSqlSource(Configuration configuration, Object provider) { this(configuration, provider, null, null); } /** * @since 3.4.5 */ /** * * @param configuration Mybatis全局配置信息 * @param provider SQL provider 注解对象 * @param mapperType 映射接口类 * @param mapperMethod 映射接口类方法对象 */ public ProviderSqlSource(Configuration configuration, Object provider, Class mapperType, Method mapperMethod) { String providerMethodName; try { this.configuration = configuration; //获取mapperMethod的Lang注解 Lang lang = mapperMethod == null ? null : mapperMethod.getAnnotation(Lang.class); //获取Lang注解对象指定的语言驱动,如果没有指定的话,默认使用XMLLanguageDriver this.languageDriver = configuration.getLanguageDriver(lang == null ? null : lang.value()); //通过反射获取SQL provider注解的type方法指定的SQL脚本提供者类 this.providerType = (Class) provider.getClass().getMethod("type").invoke(provider); //通过反射获取SQL provider注解的method方法指定的SQL脚本提供者类的方法的映射方法名 providerMethodName = (String) provider.getClass().getMethod("method").invoke(provider); //如果方法名不是空字符 且 SQL脚本提供者是ProviderMethoResolver的子类 if (providerMethodName.length() == 0 && ProviderMethodResolver.class.isAssignableFrom(this.providerType)) { /** * 构建providerType的实例对象,强转成ProviderMethodResolver类,构建一个ProviderContext对象, * 传入resolverMethod方法得到对应的Sql provider 方法,赋值给providerMethod */ this.providerMethod = ((ProviderMethodResolver) this.providerType.getDeclaredConstructor().newInstance()) .resolveMethod(new ProviderContext(mapperType, mapperMethod, configuration.getDatabaseId())); } //如果provideMethod方法为null if (this.providerMethod == null) { //如果映射方法名为空字符串,就使用默认使用'provideSql'充当映射方法名;否则使用原来的 providerMethodName = providerMethodName.length() == 0 ? "provideSql" : providerMethodName; //获取SQL脚本提供者类的所有方法 for (Method m : this.providerType.getMethods()) { //如果m等于映射方法名 且 m返回类型是CharSequence的子类 if (providerMethodName.equals(m.getName()) && CharSequence.class.isAssignableFrom(m.getReturnType())) { //如果providerMethod不为null,该判断意味着出现多个匹配的方法 if (this.providerMethod != null) { //抛出异常 throw new BuilderException("Error creating SqlSource for SqlProvider. Method '" + providerMethodName + "' is found multiple in SqlProvider '" + this.providerType.getName() + "'. Sql provider method can not overload."); } //将m赋值给providerMethod this.providerMethod = m; } } } } catch (BuilderException e) { throw e; } catch (Exception e) { throw new BuilderException("Error creating SqlSource for SqlProvider. Cause: " + e, e); } //如果provideMethod为null,意味着在providerType中没有找到匹配方法 if (this.providerMethod == null) { //抛出异常 throw new BuilderException("Error creating SqlSource for SqlProvider. Method '" + providerMethodName + "' not found in SqlProvider '" + this.providerType.getName() + "'."); } //ParamNameResolver:参数名称解析器,用于构建sql脚本参数名+参数对象映射集合 //通过ParamNameResolver获取sql脚本的参数名并赋值给providerMethodArgumentNames this.providerMethodArgumentNames = new ParamNameResolver(configuration, this.providerMethod).getNames(); //获取providerMethod的参数类型数组赋值给providerMethodParameterTypes this.providerMethodParameterTypes = this.providerMethod.getParameterTypes(); //遍历参数类型数组 for (int i = 0; i < this.providerMethodParameterTypes.length; i++) { //获取参数 Class parameterType = this.providerMethodParameterTypes[i]; //ProviderContext:Sql provider 方法的上下文对象,封装着映射接口类,映射接口类方法对象, 数据库ID //如果参数类型为ProviderContext类型 if (parameterType == ProviderContext.class) { //如果providerContext不为null,这里意味着providerContext在方法中出现了多个 if (this.providerContext != null) { //抛出异常 throw new BuilderException("Error creating SqlSource for SqlProvider. ProviderContext found multiple in SqlProvider method (" + this.providerType.getName() + "." + providerMethod.getName() + "). ProviderContext can not define multiple in SqlProvider method argument."); } //新建一个ProviderContext赋值给providerContext this.providerContext = new ProviderContext(mapperType, mapperMethod, configuration.getDatabaseId()); //将ProvideContext类型参数的索引位置赋值给providerContextIndex this.providerContextIndex = i; } } } /** * 传入 {@code parameterObject} ,然后获取参数映射与可执行SQL封装类对象 * @param parameterObject 参数对象 * @return 已绑定参数对象的参数映射与可执行SQL封装类对象 */ @Override public BoundSql getBoundSql(Object parameterObject) { //构建动态SQL,并绑定参数对象 SqlSource sqlSource = createSqlSource(parameterObject); //传入参数对象,然后获取参数映射与可执行SQL封装类对象,然后返回出去 return sqlSource.getBoundSql(parameterObject); } /** * 构建动态SQL,并绑定参数对象 * @param parameterObject 参数对象 * @return SQL源 */ private SqlSource createSqlSource(Object parameterObject) { try { //绑定参数数量等于 SQL provider 的对应映射器方法的方法对象的参数类型数组长度 - // 一个providerContext类型参数,如果providerContext为null,就是-0,否则就是-1 int bindParameterCount = providerMethodParameterTypes.length - (providerContext == null ? 0 : 1); String sql; //如果SQL provider 的对应映射器方法的方法对象的参数类型数组长度为0时 if (providerMethodParameterTypes.length == 0) { //执行 SQL provider 的对应映射器方法的方法得到Sql脚本 sql = invokeProviderMethod(); //如果绑定的参数数量为0 } else if (bindParameterCount == 0) { //执行 SQL provider 的对应映射器方法的方法,并传入providerContext, 得到Sql脚本 sql = invokeProviderMethod(providerContext); //如果绑定参数数量为1 且 第一个非ProviderContext类型的参数其参数类型属于parameterObject的父类或者同一个类型 } else if (bindParameterCount == 1 && (parameterObject == null || providerMethodParameterTypes[providerContextIndex == null || providerContextIndex == 1 ? 0 : 1].isAssignableFrom(parameterObject.getClass()))) { /** * 转换 SQL provider 的对应映射器方法的方法的参数为参数对象数组,然后执行 SQL provider 的对应映射器方法的方法, * 并传入该参数对象数组,得到SQL脚本 */ sql = invokeProviderMethod(extractProviderMethodArguments(parameterObject)); //如果参数对象是Map的子类 } else if (parameterObject instanceof Map) { //强制转换参数对象为Map类型,并赋值params @SuppressWarnings("unchecked") Map params = (Map) parameterObject; /** * 转换 SQL provider 的对应映射器方法的方法的参数为参数对象数组,然后执行 SQL provider 的对应映射器方法的方法, * 并传入该参数对象数组,得到SQL脚本 */ sql = invokeProviderMethod(extractProviderMethodArguments(params, providerMethodArgumentNames)); } else { //如果provideMethod出现多个参数(不包含ProviderContext),就会抛出异常. throw new BuilderException("Error invoking SqlProvider method (" + providerType.getName() + "." + providerMethod.getName() + "). Cannot invoke a method that holds " + (bindParameterCount == 1 ? "named argument(@Param)" : "multiple arguments") + " using a specifying parameterObject. In this case, please specify a 'java.util.Map' object."); } //获取paramterObject的参数类型并赋值给parameterType Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); //通过语音驱动构建动态SQL return languageDriver.createSqlSource(configuration, sql, parameterType); } catch (BuilderException e) { throw e; } catch (Exception e) { throw new BuilderException("Error invoking SqlProvider method (" + providerType.getName() + "." + providerMethod.getName() + "). Cause: " + e, e); } } /** * 转换 SQL provider 的对应映射器方法的方法的参数为参数对象数组 * @param parameterObject 参数对象 * @return 存放参数的object类型数组对象 */ private Object[] extractProviderMethodArguments(Object parameterObject) { //如果方法中存在providerContext类型参数 if (providerContext != null) { //定义一个长度为2的Object类型数组 Object[] args = new Object[2]; //将parameterObject赋值给非ProviderConetxt类型的参数索引位置的元素 args[providerContextIndex == 0 ? 1 : 0] = parameterObject; //将providerContext赋值給ProviderConetxt类型的参数索引位置的元素 args[providerContextIndex] = providerContext; //返回args return args; //如果方法中不存在providerContext类型参数 } else { //新建一个Object类型数组对象,并将parameterObject添加到object类型数组对象中 return new Object[] { parameterObject }; } } /** * 转换 SQL provider 的对应映射器方法的方法的参数为参数对象数组 * @param params 参数对象 * @param argumentNames SQL provider 的对应映射器方法的方法对象的SQL脚本参数名数组 * @return 存放参数的object类型数组对象 */ private Object[] extractProviderMethodArguments(Map params, String[] argumentNames) { //新建一个长度为参数名数组长度的Object类型数组赋值给args Object[] args = new Object[argumentNames.length]; //遍历args for (int i = 0; i < args.length; i++) { //如果有ProvideMethod有定义ProviderContext类型参数,且 i 等于 ProviderContext类型参数的所在索引位置 if (providerContextIndex != null && providerContextIndex == i) { //将providerContext赋值给args[i] args[i] = providerContext; //如果ProvideMethod没有定义ProviderContext类型参数 } else { //获取参数名对应参数对象,赋值给args[i] args[i] = params.get(argumentNames[i]); } } return args; } /** * 执行 SQL provider 的对应映射器方法的方法,并传入 {@code args}, 得到Sql脚本,返回返回出去 * @param args 参数对象数组 * @return Sql脚本字符串 */ private String invokeProviderMethod(Object... args) throws Exception { Object targetObject = null; //如果providerMethod不是静态方法 if (!Modifier.isStatic(providerMethod.getModifiers())) { //新建一个providerType的实例对象赋值给targetObject targetObject = providerType.newInstance(); } //直接targetObject的providerMethod方法,并传入参数,然后得到SQL脚本字符串赋值給sql CharSequence sql = (CharSequence) providerMethod.invoke(targetObject, args); //如果sql不为null,返回sql;否则返回null return sql != null ? sql.toString() : null; } }

RawSqlSource

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.scripting.defaults;

import java.util.HashMap;

import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicContext;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.session.Configuration;

/**
 * Static SqlSource. It is faster than {@link DynamicSqlSource} because mappings are
 * calculated during startup.
 * 

* 调用 SqlSourceBuilder类将"#{xxx}“ 替换为占位符”?",并绑定ParameterMapping, * 最后返回的RawSqlSource中持有一个由SqlSourceBuilder构建的SqlSource对象。 *

* @since 3.2.0 * @author Eduardo Macarron */ public class RawSqlSource implements SqlSource { /** * 实际为StaticSqlSource */ private final SqlSource sqlSource; /** * * @param configuration mybatis全局配置信息 * @param rootSqlNode DML标签下的子节点,封装成MixedSqlNode * @param parameterType 参数类型 */ public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class parameterType) { this(configuration, getSql(configuration, rootSqlNode), parameterType); } /** * * @param configuration mybatis全局配置信息 * @param sql 完整可执行SQL * @param parameterType 参数类型 */ public RawSqlSource(Configuration configuration, String sql, Class parameterType) { //解析 SQL 语句,并构建 StaticSqlSource,在此过程中将 sql 语句中的占位符 #{} 替换为问号 ?,并为每个占位符构建相应的 ParameterMapping SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class clazz = parameterType == null ? Object.class : parameterType; //实际创建的为:StaticSqlSource sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>()); } /** * 通过遍历所有的SqlNode,获取sql * @param configuration mybatis全局配置信息 * @param rootSqlNode DML标签下的子节点,封装成MixedSqlNode * @return 完整可执行的sql */ private static String getSql(Configuration configuration, SqlNode rootSqlNode) { DynamicContext context = new DynamicContext(configuration, null); rootSqlNode.apply(context); return context.getSql(); } @Override public BoundSql getBoundSql(Object parameterObject) { return sqlSource.getBoundSql(parameterObject); } }

StaticSqlSource

/**
 *    Copyright 2009-2017 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.builder;

import java.util.List;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;

/**
 * 静态SQL源
 * @author Clinton Begin
 */
public class StaticSqlSource implements SqlSource {

  /**
   * 可执行的完整SQL
   */
  private final String sql;
  /**
   * {@link #sql} 的参数映射集合
   */
  private final List parameterMappings;
  /**
   * mybatis全局配置信息
   */
  private final Configuration configuration;

  /**
   *
   * @param configuration mybatis配置信息
   * @param sql 可执行的完整SQL
   */
  public StaticSqlSource(Configuration configuration, String sql) {
    this(configuration, sql, null);
  }

  /**
   *
   * @param configuration mybatis配置信息
   * @param sql 可执行的完整SQL
   * @param parameterMappings mybatis全局配置信息
   */
  public StaticSqlSource(Configuration configuration, String sql, List parameterMappings) {
    this.sql = sql;
    this.parameterMappings = parameterMappings;
    this.configuration = configuration;
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    return new BoundSql(configuration, sql, parameterMappings, parameterObject);
  }

}

BoundSql

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.session.Configuration;

/**
 * An actual SQL String got from an {@link SqlSource} after having processed any dynamic content.
 * The SQL may have SQL placeholders "?" and an list (ordered) of an parameter mappings
 * with the additional information for each parameter (at least the property name of the input object to read
 * the value from).
 * 

* Can also have additional parameters that are created by the dynamic language (for loops, bind...). *

* 参数映射与可执行SQL封装类对象 *

*

* 其中包含sql语句(该sql语句中可能包含 ? 这样的占位符), 以及一组parameter mapping(ParameterMapping类的实例), * 注意这组parameter mapping是Mybatis内部生成的(通过读取#{xx}中的内容) *

*

* 再强调一次,以上的ParameterMapping实例是在 * ParameterHandler接口的唯一默认实现类 DefaultParameterHandler 中被消费的. *

*

* BoundSql更像一个中转站, Mybatis在执行一次CRUD操作过程中产生的中间数据的集中点. * 这一点观察其内部的字段就可以了解. * 内部基本没做什么处理, 只是将相应的操作调度给了内部的字段 *

*

* https://blog.csdn.net/lqzkcx3/article/details/78370497 *

* @author Clinton Begin */ public class BoundSql { /** * 进行 #{ } 和 ${ } 替换完毕之后的结果sql, 注意每个 #{ }替换完之后就是一个 ? */ private final String sql; /** * 这里的parameterMappings列表参数里的item个数, 以及每个item的属性名称等等, 都是和上面的sql中的 ? 完全一一对应的. */ private final List parameterMappings; /** * 用户传入的参数对象 */ private final Object parameterObject; /** * 额外的参数 */ private final Map additionalParameters; /** * 元对象参数,{@link #additionalParameters} 的元对象 */ private final MetaObject metaParameters; /** * * @param configuration mybatis全局配置信息 * @param sql 进行 #{ } 和 ${ } 替换完毕之后的结果sql, 注意每个 #{ }替换完之后就是一个 ? * @param parameterMappings 参数映射 * @param parameterObject 参数对象 */ public BoundSql(Configuration configuration, String sql, List parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; this.additionalParameters = new HashMap<>(); this.metaParameters = configuration.newMetaObject(additionalParameters); } /** * * @return {@see #sql} */ public String getSql() { return sql; } /** * * @return {@see #parameterMappings} */ public List getParameterMappings() { return parameterMappings; } /** * * @return {@see #parameterObject} */ public Object getParameterObject() { return parameterObject; } /** * 是否存在额外的参数 * @param name 参数 如'order[0].item[0].name' * @return 通过 {@link PropertyTokenizer} 解析 {@code name} ,再以 {@link PropertyTokenizer#getName()} * 作为参数名,判断是否存在在 {@link #additionalParameters} 中 */ public boolean hasAdditionalParameter(String name) { String paramName = new PropertyTokenizer(name).getName(); return additionalParameters.containsKey(paramName); } /** * 对额外的参数设置参数 * @param name 参数属性名 * @param value 参数值 */ public void setAdditionalParameter(String name, Object value) { metaParameters.setValue(name, value); } /** * 获取额外的参数的对应 {@code name} 的值 * @param name 参数名 * @return 对应 {@code name} 的值 */ public Object getAdditionalParameter(String name) { return metaParameters.getValue(name); } }

你可能感兴趣的:(Mybatis-SqlSource源码解析)