mybatis作为持久层,其操作数据库离不开sql语句。而BoundSql则是其保存Sql语句的对象

前提

  1. 针对mybatis的配置文件的节点解析,比如where/if/trim的节点解析可见文章Spring mybatis源码篇章-NodeHandler实现类具体解析保存Dynamic sql节点信息

  2. 针对mybatis配置文件的解析帮助类SqlSource[一般为DynamicSqlSource]的使用可见文章Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource

  3. 对BoundSql对象的调用获取可见文章Mybatis源码分析-BaseExecutor

本文将在上述的知识前提下展开对Sql语句的解析

BoundSql的引用

主要是通过MappedStatement#getBoundSql()方法调用获取的。我们可以简单跟踪下其中的源码,如下

  public BoundSql getBoundSql(Object parameterObject) {
// 通过SqlSource获取BoundSql对象
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
// 校验当前的sql语句有无绑定parameterMapping属性
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
} // check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
} return boundSql;
}

RawSqlSource-常用的mybatis解析sql帮助类

我们观察下其getBoundSql()方法,源码如下

  public BoundSql getBoundSql(Object parameterObject) {
//此处的sqlSource为RawSqlSource的内部属性
return sqlSource.getBoundSql(parameterObject);
}

我们看下sqlSource是如何生成的,由此观察其构造函数

public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {
// 通过SqlSourceBuilder来创建sqlSource
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> clazz = parameterType == null ? Object.class : parameterType;
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<String, Object>());
}

#{}的使用这里稍微提下,一般的写法都为{name,jdbcType=String,mode=out,javaType=java.lang.String...},其中jdbcType也可以不指定,系统会自动识别。上述的代码其实主要就是针对#{}字符内容的处理

注意:${}这样的字符是通过DynamicSqlSource来完成解析的,具体的解析读者可自行分析

我们可以继续看下SqlSourceBuilder类是如何解析获取sql语句的

SqlSourceBuilder#parse()

直接上源码

public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
// 对#{}这样的字符串内容的解析处理类
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
// 获取真实的可执行性的sql语句
String sql = parser.parse(originalSql);
// 包装成StaticSqlSource返回
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}

简单的看下ParameterMappingTokenHandler是如何解析的,其是TokenHandler接口的实现类,我们就关注实现方法handleToken

@Override
public String handleToken(String content) {
// 此处的作用就是对`#{}`节点中的key值保存映射,比如javaType/jdbcType/mode等信息,限于篇幅过长,读者可自行分析
parameterMappings.add(buildParameterMapping(content));
// 将`#{}`替换为?,即一般包装成`select * form test where name=? and age=?`预表达式语句
return "?";
}

上述主要通过ParameterMappingTokenHandler类来完成对#{}字符串的解析,其中的映射信息则保存至BoundSql的parameterMappings属性中

总结

  1. BoundSql语句的解析主要是通过对#{}字符的解析,将其替换成?。最后均包装成预表达式供PrepareStatement调用执行

  2. #{}中的key属性以及相应的参数映射,比如javaType、jdbcType等信息均保存至BoundSql的parameterMappings属性中供最后的预表达式对象PrepareStatement赋值使用

Mybatis源码解析-BoundSql的更多相关文章

  1. Mybatis源码解析-DynamicSqlSource和RawSqlSource的区别

    XMLLanguageDriver是ibatis的默认解析sql节点帮助类,其中的方法其会调用生成DynamicSqlSource和RawSqlSource这两个帮助类,本文将对此作下简单的简析 应用 ...

  2. 【MyBatis源码解析】MyBatis一二级缓存

    MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...

  3. Mybatis源码解析,一步一步从浅入深(七):执行查询

    一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...

  4. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  5. Mybatis源码解析(二) —— 加载 Configuration

    Mybatis源码解析(二) -- 加载 Configuration    正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...

  6. mybatis源码-解析配置文件(四-1)之配置文件Mapper解析(cache)

    目录 1. 简介 2. 解析 3 StrictMap 3.1 区别HashMap:键必须为String 3.2 区别HashMap:多了成员变量 name 3.3 区别HashMap:key 的处理多 ...

  7. mybatis源码-解析配置文件(四)之配置文件Mapper解析

    在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...

  8. mybatis源码-解析配置文件(三)之配置文件Configuration解析

    目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...

  9. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

随机推荐

  1. android.intent.action.MAIN与android.intent.category.LAUNCHER

    android.intent.action.MAIN 决定应用程序最先启动的Activity android.intent.category.LAUNCHER 决定应用程序是否显示在程序列表里 在网上 ...

  2. properties文件作用以及在哪些地方用

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...

  3. HTML表单操作的记录

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

    概述 容器,顾名思义是用来存放并容纳东西的器皿: 而容器技术伴着Docker的兴起也渐渐的映入大家的眼帘,它是一个抽象的概念,同时也是默默存在世上多年的技术,不仅能使应用程序间完全的隔离,而且还能在共 ...

  5. Java静态绑定与动态绑定

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定. 静态绑定: 在程序执行前方法已经被绑定(也就是说 ...

  6. javascript多种方法实现数组去重

    先说说这个实例的要求:写一个方法实现数组的去重.(要求:执行方法,传递一个数组,返回去重后的新数组,原数组不变,实现过程中只能用一层循环,双层嵌套循环也可写,只做参考): 先给初学者解释一下什么叫数组 ...

  7. 直播协议 HTTP-FLV 详解

    传统的直播协议要么使用 Adobe 的基于 TCP 的 RTMP 协议,要么使用 Apple 的基于 HTTP 的 HLS 协议. 今天我要向大家介绍另外一种结合了 RTMP 的低延时,以及可以复用现 ...

  8. Windows Firewall Setting

    If our web site hosted on web server canot be accessed by other computer by public network, one of t ...

  9. R的数据图形

    R支持4种图形类型: base graphics, grid graphics, lattice graphics,  ggplot2. Base graphics是R的默认图形系统. 一.  基本图 ...

  10. easyUI datagrid 列宽自适应(简单 图解)(转)

    响应数据格式: easyUI在html代码中结构: 发现了什么没有,我们的表头其实是一个td在td中有一个属性field那么我们就可以获得了; 以下就是自适应代码: //添加事件 function c ...