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. vue指令v-if示例解析

    v-if根据表达式的值的真假条件渲染元素. <div id="app"> <p v-if="isRender">this is a me ...

  2. <经验杂谈>C#生成条形码

    虽然二维码满天飞,但也不能忘了条形码,本篇介绍可以在C#中使用的1D/2D编码解码器.条形码的应用已经非常普遍,几乎所有超市里面的商品上面都印有条形码: 条形码的标准: 条形码的标准有ENA条形码.U ...

  3. JavaScript原型及继承

    一.浅谈原型 首先我们要知道创建对象的方法有两种: 1.通过字面量的方式直接创建 var obj = { name:'baimao', age:21 } 2.通过构造函数创建对象 function P ...

  4. Akka(17): Stream:数据流基础组件-Source,Flow,Sink简介

    在大数据程序流行的今天,许多程序都面临着共同的难题:程序输入数据趋于无限大,抵达时间又不确定.一般的解决方法是采用回调函数(callback-function)来实现的,但这样的解决方案很容易造成“回 ...

  5. MySQL数据库IO问题

    --MySQL数据库IO问题 ----------------------2014/05/25     看http://www.mysqlperformanceblog.com 的时候,发现Perco ...

  6. Jenkins : 邮件通知

    目录 全局配置 为项目添加邮件通知 邮件模板 Pipeline 支持 总结 Jenkins 内置了 Mailer 插件用于发送邮件通知,但是 Mailer 插件的功能比较简单,无法按照用户的需求进行邮 ...

  7. Mac实用操作技巧(六)

    Night Shift,保护你夜间的眼睛 之前在Mac上有一款很著名的软件叫f.lux,这款软件会根据Mac的时间和地理位置,来自动切换屏幕亮度,如果进入晚上则调成暖色,白天就切换成普通颜色.现在Ma ...

  8. Maven详解(二)------ Maven的安装配置

    1.下载 Maven ①.官网下载地址:http://maven.apache.org/download.cgi ②.百度云盘:http://pan.baidu.com/s/1eS1NVYa 密码:9 ...

  9. Spring(三)之自动装配、表达式

    自动装配 自动装配(autowire)协作者 Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系.因此,如果可能的话,可以自动让Spring通过检查BeanFact ...

  10. 学习笔记GAN001:生成式对抗网络,只需10步,从零开始到调试

    生成式对抗网络(gennerative adversarial network,GAN),目前最火的非监督深度学习.一个生成网络无中生有,一个判别网络推动进化.学技术,不先着急看书看文章.先把Demo ...