查询为例
查询方法由SqlSessionTemplate中创建DefaultSqlSession,然后执行DefaultSqlSession的selectList方法。
然后继续执行查询方法
执行executor.query方法,executor为CachingExecutor类型。
如果引入了pagehelper依赖,这里执行前会进入分页拦截器
关键方法是这个getBoundsql,就是通过这个方法获取到sql的。
BoundSql
public class BoundSql {
// 一个完整的 SQL 语句,可能会包含问号 ? 占位符
private final String sql;
// 参数映射列表,SQL 中的每个 #{xxx} 占位符都会被解析成相应的 ParameterMapping 对象
private final List<ParameterMapping> parameterMappings;
// 运行时参数,即用户传入的参数,比如 Article 对象,或是其他的参数
private final Object parameterObject;
// 附加参数集合,用于存储一些额外的信息,比如 datebaseId 等
private final Map<String, Object> additionalParameters;
// additionalParameters 的元信息对象
private final MetaObject metaParameters;
}
getBoundSql方法
public BoundSql getBoundSql(Object parameterObject) {
//获取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
然后执行MixedSqlNode类apply方法把 ${}的内容替换成真实数据
传入的是原始sql
TextSqlNode类的apply方法
GenericTokenParser类的parse方法
关键方法
TextSqlNode类的handleToken方法
从context拿到值,根据传进来的key
这时拿到的sql就是完整的sql了
如果是#{}
则会走StaticSqlSource类的getBoundSql方法
执行完参数还是 问号?
然后继续执行查询方法,应该是在最终查询时将实际数据传入的。
继续CachingExecutor的query方法
然后执行BaseExecutor类的query方法
没有缓存的话去数据库查询
继续BaseExecutor类的queryFromDatabase方法
先把key放入缓存,然后继续执行doQuery方法
SimpleExecutor类的doQuery方法
关键方法 prepareStatement() 方法
SimpleExecutor类的prepareStatement方法
关键方法parameterize
就是这个方法给 ?赋的值
RoutingStatementHandler类的parameterize方法
DefaultParameterHandler类的setParameters方法
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//从boundSql拿到参数的标识
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
//拿到属性名
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
//parameterObject就是传入的值
MetaObject metaObject = configuration.newMetaObject(parameterObject);
//根据key拿到value 这样就拿到了我们传入的值
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 由类型处理器 typeHandler 向 ParameterHandler 设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
至此,${} 和#{}的赋值就完成了,还需要分析的是《where》这种标签是怎么解析的,最后就是执行最终的查询了。
todo 查询后对结果进行解析