Myabtis-动态sql解析流程

2023-12-26 07:48

本文主要是介绍Myabtis-动态sql解析流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.DynamicContext 上下文

2.sqlNode接口及其主要实现类

​​​​​​​2.1. StaticTextSqlNode 和 MixedSqlNode

2.2TextSqlNode

3. IfSqlNode

4.TrimSqlNode


​​​​​​​

1.DynamicContext 上下文

  • MyBatis 解析一条动态 SQL 语句的时候,整个流程非常长,其中涉及多层方法的调用、方法的递归、复杂的循环等,产生的中间结果就是用DynamicContext 上下文对象进行存储的
  • DynamicContext 中有两个核心属性:一个是 sqlBuilder 字段(StringJoiner 类型),用来记录解析之后的 SQL 语句;另一个是 bindings 字段,用来记录上下文中的一些 KV 信息。
  • DynamicContext 定义了一个 ContextMap 内部类,ContextMap 用来记录运行时用户传入的、用来替换“#{}”占位符的实参。在 DynamicContext 构造方法中,会根据传入的实参类型决定如何创建对应的 ContextMap 对象。
public DynamicContext(Configuration configuration, Object parameterObject) {if (parameterObject != null && !(parameterObject instanceof Map)) {// 对于非Map类型的实参,会创建对应的MetaObject对象,并封装成ContextMap对象MetaObject metaObject = configuration.newMetaObject(parameterObject);boolean existsTypeHandler = configuration.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());bindings = new ContextMap(metaObject, existsTypeHandler);} else {// 对于Map类型的实参,这里会创建一个空的ContextMap对象bindings = new ContextMap(null, false);}// 这里实参对应的Key是_parameterbindings.put(PARAMETER_OBJECT_KEY, parameterObject);bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());}

2.sqlNode接口及其主要实现类

  • 组合模式(有时候也被称为“部分-整体”模式)是将同一类型的多个对象组合成一个树形结构。在使用这个树形结构的时候,我们可以像处理一个对象那样进行处理,而不用关心其复杂的树形结构
  •  SqlNode 对象就是通过组合模式组成树形结构供上层使用
public interface SqlNode {// apply()方法会根据用户传入的实参,解析该SqlNode所表示的动态SQL内容并// 将解析之后的SQL片段追加到DynamicContext.sqlBuilder字段中暂存。// 当SQL语句中全部的动态SQL片段都解析完成之后,就可以从DynamicContext.sqlBuilder字段中// 得到一条完整的、可用的SQL语句了boolean apply(DynamicContext context);}

​​​​​​​2.1. StaticTextSqlNode 和 MixedSqlNode

  • StaticTextSqlNode 用于表示非动态的 SQL 片段,其中维护了一个 text 字段(String 类型),用于记录非动态 SQL 片段的文本内容,其 apply() 方法会直接将 text 字段值追加到 DynamicContext.sqlBuilder 的最末尾。
  • MixedSqlNode 在整个 SqlNode 树中充当了树枝节点,其中维护了一个 List<SqlNode> 集合用于记录 MixedSqlNode 下所有的子 SqlNode 对象。MixedSqlNode 对于 apply() 方法的实现也相对比较简单,核心逻辑就是遍历 List<SqlNode> 集合中全部的子 SqlNode 对象并调用 apply() 方法,由子 SqlNode 对象完成真正的动态 SQL 处理逻辑。

2.2TextSqlNode

  • TextSqlNode 实现抽象了包含 “${}”占位符的动态 SQL 片段。TextSqlNode 通过一个 text 字段(String 类型)记录了包含“${}”占位符的 SQL 文本内容,在 apply() 方法实现中会结合用户给定的实参解析“${}”占位符
  • 使用 GenericTokenParser 识别“${}”占位符,在识别到占位符之后,会通过 BindingTokenParser 将“${}”占位符替换为用户传入的实参。BindingTokenParser 继承了TokenHandler 接口,在其 handleToken() 方法实现中,会根据 DynamicContext.bindings 这个 ContextMap 中的 KV 数据替换 SQL 语句中的“${}”占位符
public boolean apply(DynamicContext context) {// 创建GenericTokenParser解析器,这里指定的占位符的起止符号分别是"${"和"}"GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));// 将解析之后的SQL片段追加到DynamicContext暂存context.appendSql(parser.parse(text));return true;}
public String handleToken(String content) {// 获取用户提供的实参数据Object parameter = context.getBindings().get("_parameter");if (parameter == null) { // 通过value占位符,也可以查找到parameter对象context.getBindings().put("value", null);} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {context.getBindings().put("value", parameter);}// 通过Ognl解析"${}"占位符中的表达式,解析失败的话会返回空字符串Object value = OgnlCache.getValue(content, context.getBindings());String srtValue = value == null ? "" : String.valueOf(value); checkInjection(srtValue); // 对解析后的值进行过滤return srtValue; // 通过过滤的值才能正常返回}

3. IfSqlNode

  • IfSqlNode 实现类对应了动态 SQL 语句中的 标签,在 MyBatis 的 <if> 标签中使用可以通过 test 属性指定一个表达式,当表达式成立时,<if> 标签内的 SQL 片段才会出现在完整的 SQL 语句中。
  • 在 IfSqlNode 中,通过 test 字段(String 类型)记录了 <if> 标签中的 test 表达式,通过 contents 字段(SqlNode 类型)维护了 <if> 标签下的子 SqlNode 对象。在 IfSqlNode 的 apply() 方法实现中,会依赖 ExpressionEvaluator 工具类解析 test 表达式,只有 test 表达式为 true,才会调用子 SqlNode 对象(即 contents 字段)的 apply() 方法。需要说明的是:这里使用到的 ExpressionEvaluator 工具类底层也是依赖 OGNL 表达式实现 test 表达式解析的。

4.TrimSqlNode

在使用 <trim> 标签的时候,我们可以指定 prefix 和 suffix 属性添加前缀和后缀,也可以指定 prefixesToOverrides 和 suffixesToOverrides 属性来删除多个前缀和后缀(使用“|”分割不同字符串)。在 TrimSqlNode 中维护了同名的四个字段值,即 prefix 字段、suffix 字段(这两个是 String 类型)以及 prefixesToOverride 字段、suffixesToOverride 字段(这两个是 List<String> 类型)。

public boolean apply(DynamicContext context) {FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);// 首先执行子SqlNode对象的apply()方法完成对应动态SQL片段的解析boolean result = contents.apply(filteredDynamicContext);// 使用FilteredDynamicContext.applyAll()方法完成前后缀的处理操作filteredDynamicContext.applyAll();return result;}

这篇关于Myabtis-动态sql解析流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/538605

相关文章

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp