mybatis中对语句的解析使用了组合模式,针对不同的sql结点处理抽象出了SqlNode。详细的设计图为

什么时候创建不同的SqlSource?

创建DynamicSqlSource情况:

  • 在包含有If,Trim,foreach,choose,var,where,set结点
  • 文本中包含有${}时

其他情况创建RawSqlSource

1、ForEachSqlNode的处理

先添加open,在遍历集合时,先使用PrefixedContext添加分隔符,将对应的index以及item项添加到DynamicContext中的bindings中。然后使用FilteredDynamicContext将#{}包含的item或者index替换成#{__frch_}形式的,最后添加close

public boolean apply(DynamicContext context) {Map<String, Object> bindings = context.getBindings();final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings);if (!iterable.iterator().hasNext()) {return true;}boolean first = true;applyOpen(context);int i = 0;for (Object o : iterable) {DynamicContext oldContext = context;if (first || separator == null) {context = new PrefixedContext(context, "");} else {context = new PrefixedContext(context, separator);}int uniqueNumber = context.getUniqueNumber();// Issue #709 if (o instanceof Map.Entry) {@SuppressWarnings("unchecked") Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;applyIndex(context, mapEntry.getKey(), uniqueNumber);applyItem(context, mapEntry.getValue(), uniqueNumber);} else {applyIndex(context, i, uniqueNumber);applyItem(context, o, uniqueNumber);}contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));if (first) {first = !((PrefixedContext) context).isPrefixApplied();}context = oldContext;i++;}applyClose(context);context.getBindings().remove(item);context.getBindings().remove(index);return true;}

2、IfSqlNode的处理

判断测试条件是否返回true,如果成功,将处理子结点

public boolean apply(DynamicContext context) {if (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;}

3、TextSqlNode的处理

解析其中的${},用对应的值替换

public boolean apply(DynamicContext context) {GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));context.appendSql(parser.parse(text));return true;}private static class BindingTokenParser implements TokenHandler {private DynamicContext context;private Pattern injectionFilter;public BindingTokenParser(DynamicContext context, Pattern injectionFilter) {this.context = context;this.injectionFilter = injectionFilter;}@Overridepublic String handleToken(String content) {Object parameter = context.getBindings().get("_parameter");if (parameter == null) {context.getBindings().put("value", null);} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {context.getBindings().put("value", parameter);}Object value = OgnlCache.getValue(content, context.getBindings());String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null"checkInjection(srtValue);return srtValue;}private void checkInjection(String value) {if (injectionFilter != null && !injectionFilter.matcher(value).matches()) {throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern());}}}

4、StaticTextSqlNode的处理

直接将文本添加到DynamicContext中的sql中

public boolean apply(DynamicContext context) {context.appendSql(text);return true;}

5、ChooseSqlNode处理

如果有一个结点处理成功,则返回,否则默认处理结点

public boolean apply(DynamicContext context) {for (SqlNode sqlNode : ifSqlNodes) {if (sqlNode.apply(context)) {return true;}}if (defaultSqlNode != null) {defaultSqlNode.apply(context);return true;}return false;}

6、VarDeclSqlNode处理

解析表示式的值,然后对name=value映射关系放入到ContextMap中

public boolean apply(DynamicContext context) {final Object value = OgnlCache.getValue(expression, context.getBindings());context.bind(name, value);return true;}

7、TrimSqlNode的处理

使用FilterdDynamicContext处理完sql内容后,然后使用applyAll来处理前缀、后缀问题

public boolean apply(DynamicContext context) {FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);boolean result = contents.apply(filteredDynamicContext);filteredDynamicContext.applyAll();return result;}public void applyAll() {sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);if (trimmedUppercaseSql.length() > 0) {applyPrefix(sqlBuffer, trimmedUppercaseSql);applySuffix(sqlBuffer, trimmedUppercaseSql);}delegate.appendSql(sqlBuffer.toString());}private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {if (!prefixApplied) {prefixApplied = true;if (prefixesToOverride != null) {for (String toRemove : prefixesToOverride) {if (trimmedUppercaseSql.startsWith(toRemove)) {sql.delete(0, toRemove.trim().length());break;}}}if (prefix != null) {sql.insert(0, " ");sql.insert(0, prefix);}}}private void applySuffix(StringBuilder sql, String trimmedUppercaseSql) {if (!suffixApplied) {suffixApplied = true;if (suffixesToOverride != null) {for (String toRemove : suffixesToOverride) {if (trimmedUppercaseSql.endsWith(toRemove) || trimmedUppercaseSql.endsWith(toRemove.trim())) {int start = sql.length() - toRemove.trim().length();int end = sql.length();sql.delete(start, end);break;}}}if (suffix != null) {sql.append(" ");sql.append(suffix);}}}

8、MixSqlNode的处理

是组合结点,循环遍历各子结点处理

public boolean apply(DynamicContext context) {contents.forEach(node -> node.apply(context));return true;}

mybatis对mapper.xml的解析(三)相关推荐

  1. mybatis对mapper.xml的解析(一)

    对于mapper配置文件的解析是通过XMLMapperBuilder来完成的,其主要是解析结点为mapper下的结点 public void parse() {if (!configuration.i ...

  2. mybatis对mapper.xml的解析(二)

    对select,insert,update,delete的解析是通过buildStatementFromContext来完成的,具体的解析是XMLStatementBuilder来完成的. 支持的属性 ...

  3. Mybatis实现*mapper.xml热部署-分子级更新

    需求: 项目在开发阶段或是修复bug阶段,会有修改mybatis的mapper.xml的时候,修改一般情况都要重启才能生失效,如果是分布式项目重启有时会耗时很久,都是无尽的等待.如果频繁修改,那么时间 ...

  4. idea中 mybatis 的 mapper.xml 新建没有 头文件

    idea中 mybatis 的 mapper.xml 新建没有 头文件 解决步骤: 1.直接 settings 2.直接 选择 MybatisMapper 添加: <?xml version=& ...

  5. 扫描mybatis的mapper.xml

    扫描mybatis的mapper.xml 扫描mybatis的mapper.xml 扫描mybatis的mapper.xml <!-- 如果不添加此节点mybatis的mapper.xml文件都 ...

  6. sql server解析xml属性为表格_[Mybatis][基础支持层]mapper xml sql 解析

    该系列文章针对 Mybatis 3.5.1 版本 Mybatis 中 标签解析,主要是为了得到两大部分数据 1.Mapper.class 接口 2.SQL 执行语句,结果集映射关系等数据 在上一章中提 ...

  7. MyBatis中的Mapper.xml文件解析

    具体可以参见MyBatis中文开发文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html 我所述的主要有常用的几个标签和属性 一.parameterTy ...

  8. Mybatis配置mapper.xml的三种方式

    1.使用package 配置XXXMapper.xml所在的包 <mappers><package name="com.sun.dao"/></map ...

  9. mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明

    记录一个发现的小问题,刚刚在UserMapper.xml文件中有一段中文注释掉的内容: <!-- <resultMap id="Usermap" type=" ...

最新文章

  1. python爬虫正则表达式实例-python爬虫学习三:python正则表达式
  2. 十分钟了解Kubernetes
  3. android 自定义progressbar demo,Android 自定义进度条ColorfulProgressbar,原理简单、效果还行...
  4. 装饰模式:Decorator(转自LoveCherry)
  5. 作为 Web 开发人员我踩过哪些技术的坑?
  6. 微信公众号新浪百度云做服务器
  7. java代码读写者问题_一整套Java线上故障排查技巧,爱了!
  8. 23矩阵——LU分解、用LU 分解解线性方程组、LU分解的存在性和唯一性、对称矩阵的 L D L 分解、置换矩阵、PA=LU 分解
  9. 【洛谷P1507 NASA的食物计划】动态规划
  10. 学生签到系统c代码_c语言学生签到
  11. 春节假期,把“电影院”搬回家,泰捷WEBOX T1S 投影仪全面评测
  12. System.InvalidOperationException: Failed to deploy distro docker-desktop......
  13. 【HLA】初识HLA/RTI
  14. 网易邮箱登录php,PHP模拟登陆163邮箱发邮件及获取通讯录列表的方法
  15. wts文件生成engine文件的方法
  16. 日更第7天:Linux常用命令之rm用法
  17. 网吧流媒体服务器系统,网吧视频点播服务器架设完全攻略流媒体服务器 -电脑资料...
  18. python mongodb_Python操作MongoDB文档数据库
  19. Mac下编译太阳神三国杀源码
  20. c语言-是不是太胖了

热门文章

  1. c#大圣之路笔记——c# SqlDataReader和SqlDataAdapter区别
  2. python是高级动态编程语言-python是一种跨平台、开源、免费的高级动态编程语言,对么...
  3. 关于python语言、下列说法不正确的是-下列语句中,___________是不正确的Python语句...
  4. 没有任何基础的可以学python吗-今天就来告诉你,没有编程基础的人适不适合学python...
  5. python与excel结合-使用Excel和python来做回归分析
  6. 怎么在电脑上使用python-开始在 Windows 上使用 Python(初学者)
  7. 微软400集python课程-最强福利——来自微软的Python学习教程(开发指南)
  8. python学起来难不难-Python自学难不难,培训班推荐?
  9. python新手项目-推荐:一个适合于Python新手的入门练手项目
  10. python画图-Python数据可视化之画图