聊聊 Mybatis 的动静 Sql 之 SqlSource
构建 SqlSource 对象
当 Mapper.xml 的各个标签被解析后 SqlNode,而后 SqlSourceBuilder 进一步解决,
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;
if (configuration.isShrinkWhitespacesInSql()) {sql = parser.parse(removeExtraWhitespaces(originalSql));
} else {sql = parser.parse(originalSql);
}
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
1.ParameterMappingTokenHandler 是动态外部类,它用来保留每个占位符参数解析后的后果
2. 创立辨认 #{} 占位符的解析器 GenericTokenParser,解析 sql,最终造成 StaticSqlSource 对象
SqlSource 接口
SqlSource 接口是用来创立被数据库执行的 sql, 它只有一个 getBoundSql()办法
public interface SqlSource {BoundSql getBoundSql(Object parameterObject);
}
实现类有 DynamicSqlSource、StaticSqlSource、RawSqlSource、ProviderSqlSource、VelocitySqlSource,这里重点说一下前三个实现类
解析动静 Sql 类
DynamicSqlSource 是解析动静 sql 的类
public class DynamicSqlSource implements SqlSource {
private final Configuration configuration;
private final SqlNode rootSqlNode;
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
this.configuration = configuration;
this.rootSqlNode = rootSqlNode;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
}
}
它的 getBoundSql()办法中:
创立 DynamicContext 对象
调用 SqlNode 的 apply()办法实现对 sql 片段的解析
创立 SqlSourceBuilder 对象,调用 parse()办法进行解析 #{},替换成?占位符,返回 StaticSqlSource 对象,调用 StaticSqlSource 的 getBoundSql()办法,返回 BoundSql 对象,这里存储着 sql 语句的相干信息
返回 BoundSql 对象
解析动态 SQL 类
RawSqlSource 是解析动态 sql 文件的,在程序启动的时候就解析了
public class RawSqlSource implements SqlSource {
private final SqlSource sqlSource;
public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {this(configuration, getSql(configuration, rootSqlNode), parameterType);
}
public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> clazz = parameterType == null ? Object.class : parameterType;
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>());
}
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);
}
}
它的构造方法调用了 getSql()办法,这个办法里调用 SqlSource 的 apply()办法组装成残缺 sql,而后通过 SqlSourceBuilder 调用 parse()办法解决 #{}占位符,返回 StaticSqlSource 对象
StaticSqlSource
StaticSqlSource 类:
public class StaticSqlSource implements SqlSource {
@Override
public BoundSql getBoundSql(Object parameterObject) {return new BoundSql(configuration, sql, parameterMappings, parameterObject);
}
}
它的 getBoundSql()办法就是创立 BoundSql 对象
总结
这篇文章讲了 SqlSource 的接口和它的几个实现类,其中 DynamicSqlSource 类和 RawSqlSource 类最最终生成 StaticSqlSource 类,由 StaticSqlSource 类调用 getBoundSql()办法来创立 BoundSql 类,DynamicSqlSource 是解析动静 sql 的类,RawSqlSource 是解析动态 sql 的类,在程序启动的时候就生成 sql 了
欢送关注我的公众号:敲代码的老贾,回复“支付”赠送《Java 面试》材料,阿里,腾讯,字节,美团,饿了么等大厂