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

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表