• Mybatis—SqlSource与BoundSql


      SqlSource用于描述通过@Select、@Insert、@Delete、@Update、@SelectProvider、@InsertProvider、@DeleteProvider和@UpdateProvider等注解配置的SQL信息,或者通过XML配置文件配置的SQL信息。SqlSource接口又定义了BoundSql getBoundSql(Object parameterObject)方法来获取对SQL信息进行封装的BoundSql实例。

    SqlSource

      SqlSource接口中只定义了一个getBoundSql()方法,该方法返回一个BoundSql实例,如下源代码所示:

    public interface SqlSource {
      BoundSql getBoundSql(Object parameterObject);
    }
    
    • 1
    • 2
    • 3

      Mybatis针对SqlSource接口一共提供DynamicSqlSource、ProviderSqlSource、RawSqlSource和StaticSqlSource四种实现,

    • DynamicSqlSource,描述XML配置文件和@Select、@Update等注解配置的SQL信息,这些SQL通常包含动态SQL配置或者参数占位符,需要在Mapper调用时才能确定最终的SQL语句。
    • ProviderSqlSource,描述通过@SelectProvider、@InsertProvider、@DeleteProvider和@UpdateProvider注解配置的SQL信息。
    • RawSqlSource,描述XML配置文件中的SQL信息,与DynamicSqlSource唯一的区别在于,其只描述不包含参数占位符且在解析XML配置时就能确定的SQL信息。
    • StaticSqlSource,描述经过ProviderSqlSource、DynamicSqlSource或者RawSqlSource解析后得到的静态SQL信息。

    ProviderSqlSource

      ProviderSqlSource用于描述通过@SelectProvider、@InsertProvider、@DeleteProvider和@UpdateProvider注解配置的SQL信息,如下述代码块所示,通过@SelectProvider注解指定SqlGenerator类中的selectIds方法来构造SQL语句。

    @SelectProvider(type = SqlGenerator.class, method = "selectIds")
    List<Integer> selectIds();
    
    • 1
    • 2

      ProviderSqlSource是通过其构造函数来完成构造当前指定的SQL信息,如下源代码逻辑,ProviderSqlSource构造函数的逻辑可分为两大类,一类是正常的给属性复制,一类则是处理通过注解type和method属性指定构造SQL的信息,详情如下:

    1. 根据构造函数入参对configuration、mapperMethod和languageDriver属性进行赋值;
    2. 通过注解的type或者value属性来确定构造SQL的类;
    3. 通过注解的method属性来确定构造SQL具体的方法名称;
    4. 如果没有找到执行method且当前provider注解与ProviderMethodResolver是父子关系,就将确定的构造SQL的类的构造函数当做构造SQL具体的方法名称;
    5. 如果有明确指定构造SQL具体的方法,就从指定构造SQL的类中寻找指定的方法;
    6. 成功找到构造SQL的类和方法之后,就将所有值赋值给指定的属性。
    public ProviderSqlSource(Configuration configuration, Annotation provider,
                             Class<?> mapperType, Method mapperMethod) {
        String candidateProviderMethodName;
        Method candidateProviderMethod = null;
        try {
          // 省略当前configuration、mapperMethod和languageDriver属性的赋值
          // 获取当前provider注解指定的SQL构造类,如代码块中的type = SqlGenerator.class
          this.providerType = getProviderType(configuration, provider, mapperMethod);
          // 获取当前provider注解指定的方法,如代码块中的method = "selectIds"  
          candidateProviderMethodName = (String) provider.annotationType()
                                         .getMethod("method").invoke(provider);
    
          if (candidateProviderMethodName.length() == 0 
              		&& ProviderMethodResolver.class.isAssignableFrom(this.providerType)) {
              // 如果没有执行method且当前provider注解与ProviderMethodResolver是父子关系
              candidateProviderMethod = ((ProviderMethodResolver) this.providerType.getDeclaredConstructor().newInstance())
                .resolveMethod(new ProviderContext(mapperType, mapperMethod, configuration.getDatabaseId()));
          }
          if (candidateProviderMethod == null) {
            // 确认用于构造SQL的方法  
            candidateProviderMethodName = candidateProviderMethodName.length() == 0 
                		? "provideSql" : candidateProviderMethodName;
            // 从指定构造类中找到构造SQL的方法的Method
            for (Method m : this.providerType.getMethods()) {
              if (candidateProviderMethodName.equals(m.getName()) 
                  	&& CharSequence.class.isAssignableFrom(m.getReturnType())) {
                if (candidateProviderMethod != null) {
                  throw new BuilderException("");
                }
                candidateProviderMethod = m;
              }
            }
          }
        } 
        // 省略异常处理和部分赋值代码
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    DynamicSqlSource

      DynamicSqlSource用于描述XML配置文件和@Select、@Update等注解,通过参数占位符或者动态标签配置的动态SQL信息,其也是通过构造函数来完成对SQL信息的描述。其构造函数相对简单,就只是对属性值进行赋值,如下源代码所示。

    public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
        this.configuration = configuration;
        this.rootSqlNode = rootSqlNode;
    }
    
    • 1
    • 2
    • 3
    • 4

    RawSqlSource

      RawSqlSource用于描述XML配置文件和@Select、@Update等注解,不包含参数占位符和动态标签的SQL配置信息。RawSqlSource构造函数除了正常给属性赋值以外,还多了一步解析SQL的操作。

    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    BoundSql

      BoundSql是对SQL语句及参数信息的封装,是SqlSource解析后的结果。Executor接口所定义的方法上可以清晰地看见BoundSql是作为入参传入的,所以不难推导出Executor是将BoundSql作为SQL信息来执行SQL语句的。
      BoundSql源代码就是只是封装了SQL语句、参数映射、Mapper调用时传入的参数对象和一个反射工具类,其这几个属性对应的值都是在构造BoundSql实例时通过构造函数传入的。

    public class BoundSql {
    
      private final String sql;
      private final List<ParameterMapping> parameterMappings;
      private final Object parameterObject;
      private final Map<String, Object> additionalParameters;
      private final MetaObject metaParameters;
    
      public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {
        this.sql = sql;
        this.parameterMappings = parameterMappings;
        this.parameterObject = parameterObject;
        this.additionalParameters = new HashMap<>();
        this.metaParameters = configuration.newMetaObject(additionalParameters);
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    华为云新开源低代码引擎 TinyEngine核心亮点
    lamp搭建
    前端学习路线(三)
    Linux-命令大全
    【Transformers】第 9 章 :处理很少或没有标签
    linux usb驱动
    【C++】多态
    LeetCode中等题之分数加减运算
    【JVM】内存结构
    tf.lite
  • 原文地址:https://blog.csdn.net/Jas000/article/details/127837697