• 聊聊Mybatis的动态Sql之SqlSource


    聊聊Mybatis的动态Sql之SqlSource

    构建SqlSource对象

    当Mapper.xml的各个标签被解析后SqlNode,然后SqlSourceBuilder进一步处理,

    public SqlSource parse(String originalSql, Class parameterType, Map 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()方法中:

    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了

  • 相关阅读:
    【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(9 月 13 日论文合集)
    毕业设计 基于CNN实现谣言检测 - python 深度学习 机器学习
    bwapp下载安装
    冒泡排序bubble_sort
    结合Mockjs与Bus事件总线搭建首页导航和左侧菜单
    【论文阅读】【三维目标检测】Camera-Lidar融合的3D目标检测网络
    golang 实现四层负载均衡
    js中如何实现一个简单的防抖函数?
    AWS入门实践-S3 精细化权限控制
    【MLT】MLT多媒体框架生产消费架构解析(二)
  • 原文地址:https://blog.csdn.net/Candyz7/article/details/126461119