聊聊Mybatis的动态Sql之SqlSource

举报
周杰伦本人 发表于 2022/08/30 13:41:57 2022/08/30
【摘要】 聊聊Mybatis的动态Sql之SqlSource 构建SqlSource对象 SqlSource接口 解析动态Sql类 解析静态SQL类 StaticSqlSource 总结 聊聊Mybatis的动态Sql之SqlSource 构建SqlSource对象SqlSource对象的构建是当Mapper.xml的各个标签被解析后SqlNode,然后通过SqlSourceBuilder进一步处理...

聊聊Mybatis的动态Sql之SqlSource

构建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接口

SqlSource接口是用来创建被数据库执行的sql,它只有一个getBoundSql()方法

public interface SqlSource {

  BoundSql getBoundSql(Object parameterObject);

}

方法顾名思义就是获取BoundSql对象的,那么BoundSql是干什么的呢?它其实就是sql的描述信息类,包括把sql中的井号变成问号

实现类有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;
  }

}

我们看一下这个类的获取BoundSql对象的业务逻辑
它的getBoundSql()方法中:

  1. 创建DynamicContext对象
  2. 调用SqlNode的apply()方法完成对sql片段的解析
  3. 创建SqlSourceBuilder对象,调用parse()方法进行解析#{},替换成?占位符,返回StaticSqlSource对象,
  4. 调用StaticSqlSource的getBoundSql()方法,返回BoundSql对象,这里存储着sql语句的相关信息
  5. 返回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了

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。