当前位置: 首页 > news >正文

Mybatis的SqlSource SqlNode BoundSql

学习链接

MyBatis SqlSource解析

【Mybatis】Mybatis源码之SqlSource#getBoundSql获取预编译SQL

Mybatis中SqlSource解析流程详解

Mybatis TypeHandler解析

图解

Mybatis的SqlSource&SqlNode - processon

在这里插入图片描述

DynamicSqlSource

public class DynamicSqlSource implements SqlSource {private final Configuration configuration;private final SqlNode rootSqlNode;public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {this.configuration = configuration;this.rootSqlNode = rootSqlNode;}/*** 获取一个BoundSql对象** DynamicSqlSource和 RawSqlSource都会转化为 StaticSqlSource,然后才能给出一个 BoundSql对象。** @param parameterObject 参数对象* @return BoundSql对象*/@Overridepublic BoundSql getBoundSql(Object parameterObject) {// 创建DynamicSqlSource的辅助类,用来记录DynamicSqlSource解析出来的SQL片段信息和参数信息DynamicContext context = new DynamicContext(configuration, parameterObject);// 这里会从根节点开始,对节点逐层调用apply方法,经过这一步后,动态节点"${}"都被替换,这样 DynamicSqlSource便不再是动态的,而是静态的。rootSqlNode.apply(context);// 处理占位符,汇总参数信息SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);	    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();// 使用SqlSourceBuilder处理"#{}",将其转化为"?",然后创建ParameterMapping,最终生成了StaticSqlSource对象SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());BoundSql boundSql = sqlSource.getBoundSql(parameterObject);// 把context.getBindings()的参数放到boundSql的metaParameters中进行保存context.getBindings().forEach(boundSql::setAdditionalParameter);return boundSql;}}	

RawSqlSource

通过观察RawSqlSource与DynamicSqlSource的区别,可以注意到:

  1. 首先需要判定在mapper.xml中写的一个sql标签语句到底是动态sqlSource还是rawSqlSource?这个在XMLScriptBuilder#parseDynamicTags中有解析过程,凡是含有${} 或者 还有动态标签(如trim,where,if等9个标签)的 的都是动态的
  2. DynamicSqlSource和RawSqlSource有什么共同点和区别?它们都有解析阶段 和 运行阶段,在解析阶段时,RawSqlSource在构造方法中就已经得到了StaticSqlSource了(因为里面没有需要动态解析的内容了,注意#{}不属于动态解析的范畴,只有那9个动态标签和${}才算动态的),而DynamicSqlSource需要在运行阶段根据传参,才能获得StaticSqlSource,需要根据实际传参才能确定sql,所以叫动态嘛。所以它们最终都会获取StaticSqlSource,参与后面的流程。
public class RawSqlSource implements SqlSource {private final SqlSource sqlSource;public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {this(configuration, getSql(configuration, rootSqlNode), parameterType);}public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);Class<?> clazz = parameterType == null ? Object.class : parameterType;sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>());}private static String getSql(Configuration configuration, SqlNode rootSqlNode) {DynamicContext context = new DynamicContext(configuration, null);rootSqlNode.apply(context);return context.getSql();}@Overridepublic BoundSql getBoundSql(Object parameterObject) {return sqlSource.getBoundSql(parameterObject);}}

GenericTokenParser#parse

/*** 该方法主要 完成占位符的定位工作,然后把占位符的替换工作交给与其关联的 TokenHandler 处理* @param text* @return*/
public String parse(String text) {if (text == null || text.isEmpty()) {return "";}// search open token// 查找openToken的位置int start = text.indexOf(openToken);if (start == -1) {return text;}char[] src = text.toCharArray();int offset = 0;final StringBuilder builder = new StringBuilder();StringBuilder expression = null;// 当存在openToken时,才继续处理while (start > -1) {if (start > 0 && src[start - 1] == '\\') {// this open token is escaped. remove the backslash and continue.builder.append(src, offset, start - offset - 1).append(openToken);offset = start + openToken.length();} else {// found open token. let's search close token.if (expression == null) {expression = new StringBuilder();} else {expression.setLength(0);}// 拼接从0到openToken之前的字符builder.append(src, offset, start - offset);// 设置offset值为openToken结束的位置offset = start + openToken.length();// 从offset值之后开始找第一个closeToken的位置int end = text.indexOf(closeToken, offset);// 如果存在,则继续处理while (end > -1) {if (end > offset && src[end - 1] == '\\') {// this close token is escaped. remove the backslash and continue.expression.append(src, offset, end - offset - 1).append(closeToken);offset = end + closeToken.length();// 继续查找当前closeToken之后的closeTokenend = text.indexOf(closeToken, offset);} else {expression.append(src, offset, end - offset);break;}}// 如果不存在if (end == -1) {// close token was not found.// 拼接剩余的字符builder.append(src, start, src.length - start);// 设置offset为字符数组的长度offset = src.length;} else {/*** DynamicCheckerTokenParser:如果存在,则设置当前SQL为动态的* BindingTokenParser:获取$变量的值* ParameterMappingTokenHandler:将#替换为?,并构建参数映射ParameterMapping*/builder.append(handler.handleToken(expression.toString()));// 设置offset值为closeToken结束的位置offset = end + closeToken.length();}}start = text.indexOf(openToken, offset);}// 拼接剩余的字符if (offset < src.length) {builder.append(src, offset, src.length - offset);}return builder.toString();
}

相关文章:

Mybatis的SqlSource SqlNode BoundSql

学习链接 MyBatis SqlSource解析 【Mybatis】Mybatis源码之SqlSource#getBoundSql获取预编译SQL Mybatis中SqlSource解析流程详解 Mybatis TypeHandler解析 图解 Mybatis的SqlSource&SqlNode - processon DynamicSqlSource public class DynamicSqlSource implement…...

html动态爱心代码【二】(附源码)

目录 前言 效果演示 内容修改 完整代码 总结 前言 七夕马上就要到了&#xff0c;为了帮助大家高效表白&#xff0c;下面再给大家带来了实用的HTML浪漫表白代码(附源码)背景音乐&#xff0c;可用于520&#xff0c;情人节&#xff0c;生日&#xff0c;表白等场景&#xff0c…...

【Rust】Rust学习 第十六章无畏并发

安全且高效的处理并发编程是 Rust 的另一个主要目标。并发编程&#xff08;Concurrent programming&#xff09;&#xff0c;代表程序的不同部分相互独立的执行&#xff0c;而 并行编程&#xff08;parallel programming&#xff09;代表程序不同部分于同时执行&#xff0c;这两…...

系统报错mfc100u.dll丢失的解决方法(完美解决dll问题)

系统文件mfc100u.dll丢失和出错&#xff0c;极有可能是盗号木马、流氓软件等恶意程序所导致&#xff0c;其感染相关文件并加载起来&#xff0c;一旦杀毒软件删除被感染的文件&#xff0c;就会导致相关组件缺失&#xff0c;游戏等常用软件运行不起来&#xff0c;且提示“无法启动…...

docker compose的用法

目录 一、Docker-Compose介绍 1.1 Docker-Compose的概述 1.2 Docker-Compose 用来实现Docker容器快速编排 1.3 Docker-compose模板文件简介 二、YAML简介 2.1 YAML的概述 2.2 YAML的基本语法规则 2.3 YAML支持的数据架构 三、配置内部常用字段 四、Docker-compose 常…...

Linux: 使用 ssh 连接其他服务器

通过ifconfig 查看要连接的服务器地址&#xff1a; ubuntuubuntu1804-0172:/media/sangfor/vdc$ ssh ubuntu192.168.11.49 输入要连接的服务器密码: ubuntua192.168.1149 s password: 连接服务器成功&#xff1a;...

[.NET/WPF] CommunityToolkit.Mvvm 异步指令

我们在开发中, 经常会有这样的需求: 点击按钮后, 进行一些耗时的工作工作进行时, 按钮不可再次被点击工作进行时, 会显示进度条, 或者 “加载中” 的动画 RelayCommand CommunityToolkit.Mvvm 中的 RelayCommand 除了支持最简单的同步方法, 还支持以 Task 作为返回值的异步方…...

热烈祝贺汇隆成功入选航天系统采购供应商库

经过航天系统采购平台的严审&#xff0c;浙江汇隆晶片技术有限公司成功入选中国航天系统采购供应商库。航天系统采购平台是航天系统内企业采购专用平台&#xff0c;服务航天全球范围千亿采购需求&#xff0c;目前&#xff0c;已有华为、三一重工、格力电器、科大讯飞等企业、机…...

2019年3月全国计算机等级考试真题(C语言二级)

2019年3月全国计算机等级考试真题&#xff08;C语言二级&#xff09; 第1题 负责数据库中查询操作的数据库语言是 A. 数据定义语言 B. 数据管理语言 C. 数据操纵语言 D. 数据控制语言 正确答案&#xff1a;C 第2题 有关系如下图所示&#xff0c;其违反了哪一类完整性约束 …...

MySQL 游标

文章目录 1.游标是什么2.MySQL 游标3.定义游标4.打开游标5.提取数据6.关闭游标参考文献 1.游标是什么 游标&#xff08;Cursor&#xff09;是一种用于处理查询结果集的数据库对象&#xff0c;它允许开发者按照特定的顺序逐行遍历查询结果集中的数据。游标通常用于在数据库中执…...

ElasticSearch 7.4学习记录(DSL语法)

上文和大家一起初次了解了很多ES相关的基础知识&#xff0c;本文的内容将会是实际企业中所需要的吗&#xff0c;也是我们需要熟练应用的内容。 面对ES&#xff0c;我们最多使用的就是查询&#xff0c;当我负责这个业务时&#xff0c;现不需要我去考虑如何创建索引&#xff0c;添…...

全志orangepi-zero2驱动编写2,控制电平高低

使用驱动编写控制高低电平 可看我前俩篇文章&#xff1a; 【1】全志orangepi-zeor2驱动编写 【2】驱动函数框架详解 检索芯片手册关键信息 知道GPIO基地址 知道PC偏移地址 知道想要控制的端口的信息 知道数据位如何操作 代码实操 驱动代码 #include <linux/fs.h&…...

软考高级系统架构设计师系列之:论文典型试题写作要点和写作素材总结系列文章四

软考高级系统架构设计师系列之:论文典型试题写作要点和写作素材总结系列文章四 一、论软件的静态演化和动态演化及其应用1.论文题目2.写作要点和写作素材二、论大规模分布式系统缓存设计策略1.论文题目2.写作要点和写作素材三、论基于REST服务的Web应用系统设计1.论文题目2.写…...

06.利用Redis实现点赞功能

学习目标&#xff1a; 提示&#xff1a;学习如何利用Redisson实现点赞功能 学习产出&#xff1a; 解决方案&#xff1a; 点赞后的用户记录在Redis的set数据类型中 1. 准备pom环境 <dependency><groupId>org.springframework.boot</groupId><artifactI…...

【React】生命周期和钩子函数

概念 组件从被创建到挂载到页面中运行&#xff0c;再到组件不用时卸载的过程。 只有类组件才有生命周期。 分为三个阶段&#xff1a; 挂载阶段更新阶段销毁阶段 三个阶段 挂载阶段 钩子函数 - constructor 创建阶段触发 作用&#xff1a;创建数据 之前定义状态是简写&…...

无涯教程-TensorFlow - 优化器

Optimizers是扩展类&#xff0c;其中包括用于训练特定模型的附加信息&#xff0c;Optimizers类使用给定的参数初始化&#xff0c;用于提高速度和性能&#xff0c;以训练特定模型。 TensorFlow的基本Optimizers是- tf.train.Optimizer 此类在tensorflow/python/training/opti…...

基于AQS+双向链表实现队列先进先出

学习AQS写的一个模拟案例 package com.tom.xiangyun.ch04_aqs;import com.tom.tuling.UnsafeFactory; import sun.misc.Unsafe;import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock;/*** 使用双向链表实现队列** author 钟棋…...

无涯教程-Perl - time函数

描述 此函数返回自纪元以来的秒数(对于大多数系统,是1970年1月1日UTC,00:00:00&#xff1b;对于Mac OS,是1904年1月1日,00:00:00)。适用于gmtime和本地时间。 语法 以下是此函数的简单语法- time返回值 此函数返回自纪元后数秒的整数。 例 以下是显示其基本用法的示例代…...

CUDA Bug<三>当__global__函数出现里面所有输出的数组都随机赋值了

问题具体描述&#xff1a; eg. __global__ void Updata_HomJm(float* H,float *HJm,float* fr,float *gr,float* ur,float* urgrJm,float*wpd,float *w, float *wJm,int n) { int idx blockIdx.x*blockDim.x threadIdx.x;float t 0.0;//H*zpint idx_Ai idx*n;for (int j…...

甜椒叶病害识别(Python代码,pyTorch框架,深度卷积网络模型,很容易替换为其它模型,带有GUI识别界面)

代码运行要求&#xff1a;Torch>1.13.1即可 1.数据集介绍&#xff1a; 第一个文件夹是细菌斑叶&#xff08;3460张&#xff09; 第二个文件夹是 健康&#xff08;4024张&#xff09; 2.整个文件夹 data文件夹存放的是未被划分训练集和测试集的原始照片 picture文件夹存放的…...

Python爬虫——scrapy_日志信息以及日志级别

日志级别&#xff08;由高到低&#xff09; CRITICAL&#xff1a; 严重错误 ERROR&#xff1a; 一般错误 WARNING&#xff1a; 警告 INFO&#xff1a; 一般警告 DEBUG&#xff1a; 调试信息 默认的日志等级是DEBUG 只要出现了DEBUG或者DEBUG以上等级的日志&#xff0c;那么这些…...

微信小程序 echarts 画多个横向柱状图

然后是json {"usingComponents": {"ec-canvas": "../../common/ec-canvas/ec-canvas"},"navigationBarTitleText": "主题活动" } ec-canvas获取方式 在链接里下载代码 然后copy ec-canvas文件夹到自己的项目 https://gi…...

【二叉树】572. 另一棵树的子树

572. 另一棵树的子树 解题思路 遍历二叉树的思路针对每一个节点判断该节点的子树和subtree是不是相等需要编写判断两个子树是否相等的函数 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* …...

220V转5V芯片三脚芯片-AH8652

220V转5V芯片三脚芯片是一种非常常见的电源管理芯片&#xff0c;它通常被用于将高压交流输入转为稳定的直流5V输出。芯片型号AH8652是一款支持交流40V-265V输入范围的芯片&#xff0c;采用了SOT23-3三脚封装。该芯片内部集成了650V高压MOS管&#xff0c;能够稳定地将输入电压转…...

windows系统丢失mfc120u.dll的解决方法

1.mfc120u.dll是什么 mfc120u.dll是Windows操作系统中的一个动态链接库&#xff08;Dynamic Link Library&#xff0c;简称DLL&#xff09;文件。它包含了一些用于运行C程序的函数和其他资源。这个特定的DLL文件是Microsoft Foundation Classes&#xff08;MFC&#xff09;库的…...

css 实现电梯导航

实现原理&#xff1a;利用css实现电梯导航很简单&#xff0c;基本原理就是通过a标签绑定跳转目标的id来实现的 html代码&#xff1a; <div class"body"><div class"top" id"top"></div><div class"con1" id"…...

【Spring Boot】Spring Retry减少1000 行代码讲解

文章目录 前言问题介绍解决方案Let’s start hacking!1. 设置 Spring 重试2. 重构代码 总结 前言 本文翻译自国外论坛 medium&#xff0c;原文地址&#xff1a;levelup.gitconnected.com/how-i-delet…&#xff0c;原文作者&#xff1a;Hari Ohm Prasath 使用 Spring Retry 重…...

【数据结构OJ题】相交链表

原题链接&#xff1a;https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 看到这道题&#xff0c;很容易想到的方法就是暴力求解&#xff0c;就是将一个链表的每个结点的地址…...

【华为OD机试】最小传输时延I【2023 B卷|200分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 某通信网络中有N个网络结点,用1到N进行标识。网络通过一个有向无环图表示, 其中图的边的值表示结点之间的消息传递时延。 现给定相连节点之间的时延列表times[i]={u,v,w},其中u表示…...

Android13 网络 Adb 默认开启

Android 13 网络 Adb 默认开启 文章目录 Android 13 网络 Adb 默认开启一、前言二、默认adb 代码实现1、修改的目录&#xff1a;2、具体修改&#xff1a;&#xff08;1&#xff09;在XXX_device.mk 添加属性&#xff08;2&#xff09;设置固定端口号&#xff08;3&#xff09;去…...

怎么做一考试网站/最新新闻国内大事件

我今天新建了一个项目&#xff0c;但是在这里却看不到手机的界面效果&#xff0c;如下图&#xff1a; 打开文件res/values/styles.xml&#xff0c; 将下面的代码 <style name"AppTheme" parent"Theme.AppCompat.Light.DarkActionBar"><!-- Custom…...

wordpress 动画主题/镇江搜索优化技巧

点击上方【凌云驭势 重塑未来】一起共赴年度科技盛宴&#xff01;在现代应用程序开发和数据处理领域&#xff0c;使用 Apache Kafka 作为数据管道和扇出方法的标准传输机制已成为一种常见趋势。 Amazon Managed Streaming for Apache Kafka9 (Amazon MSK) 是一项完全托管的、高…...

网站空间可以自己做吗/最新国际新闻热点事件

原因一&#xff1a;没有打开MSDTC服务 步骤&#xff1a; Componet Services-->右击My Computer--->Start MSDTCComponet Services-->右击My Computer-->属性--->MSDTC-->安全配置--->勾选上我红线标注的部分。原因二&#xff1a; 防火墙阻止 解决方法&…...

减少网站跳出率/站长统计官网

一、为什么要挂载windows分区 随着linux越来越普及&#xff0c;很多linux FANS正在或者已经从windows系统过度到linux系统上了。在这个过度时期&#xff0c;大部分FANS在自己的机器上都是至少装了两套系统——windows和linux。这样&#xff0c;问题就出现了&#xff0c;当FANS们…...

做网站费用上海/百度打开百度搜索

在Tableadapter里面用%x%&#xff0c;应该是不行的&#xff0c;经过了测试&#xff0c; 有两种解决办法&#xff0c; 1种是&#xff1a;通过存储过程&#xff0c;参见&#xff1a; http://forums.asp.net/t/1390313.aspx 1种是通过类似&#xff0c;WHERE CharIndex(x, book_inf…...

做网站用什么/企业邮箱怎么开通注册

MySQL数据字典相关的sql查询和navicat的一个导出ER图功能##mysql 查看表结构SELECTCOLUMN_NAME Field,COLUMN_TYPE Type,IS_NULLABLE Null,COLUMN_KEY Key,COLUMN_DEFAULT Default,COLUMN_COMMENT CommentFROMINFORMATION_SCHEMA.COLUMNSWHEREtable_schema dbname ##数据库名A…...