Mybatis3.5.1源码分析
- Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
- Mybatis-Configuration源码解析
- Mybatis-事务对象源码解析
- Mybatis-数据源源码解析
- Mybatis缓存策略源码解析
- Mybatis-DatabaseIdProvider源码解析
- Mybatis-TypeHandler源码解析
- Mybatis-Reflector源码解析
- Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
- Mybatis-Mapper各类标签封装类源码解析
- Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
- Mybatis-MapperAnnotationBuilder源码分析
- [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
- Mybatis-LanguageDriver源码解析
- Mybatis-SqlSource源码解析
- Mybatis-SqlNode源码解析
- Mybatis-KeyGenerator源码解析
- Mybatis-Executor源码解析
- Mybatis-ParameterHandler源码解析
- Mybatis-StatementHandler源码解析
- Mybatis-DefaultResultSetHandler(一)源码解析
- Mybatis-DefaultResultSetHandler(二)源码解析
- Mybatis-ResultHandler,Cursor,RowBounds 源码分析
- Mybatis-MapperProxy源码解析
- Mybatis-SqlSession源码解析
- 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);
}
}