聊聊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面试》材料,阿里,腾讯,字节,美团,饿了么等大厂