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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/101274.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

05-微信小程序常用组件-表单组件

05-微信小程序常用组件-表单组件 文章目录 表单组件button 按钮案例代码 form 表单案例代码 image 图片支持长按识别的码案例代码 微信小程序包含了六大组件&#xff1a; 视图容器、 基础内容、 导航、 表单、 互动和 导航。这些组件可以通过WXML和WXSS进行布局和样式设…

800V高压电驱动系统架构分析

需要电驱竞品样件请联&#xff1a;shbinzer &#xff08;拆车邦&#xff09; 过去一年是新能源汽车市场爆发的一年&#xff0c;据中汽协数据&#xff0c;2021年新能源汽车销售352万辆&#xff0c;同比大幅增长157.5%。新能源汽车技术发展迅速&#xff0c;畅销车辆在动力性能…

【Python原创设计】基于Python Flask的全国气象数据采集及可视化系统-附下载方式以及项目参考论文,原创项目其他均为抄袭

基于Python Flask的全国气象数据采集及可视化系统 一、项目简介二、项目技术三、项目功能四、运行截图五、分类说明六、实现代码七、数据库结构八、源码下载 一、项目简介 本项目是一个基于Web技术的实时气象数据可视化系统。通过爬取中国天气网的各个城市气象数据&#xff0c…

Nginx高可用集群

目录 一.简介二.案例1.实现思路2.配置文件修改3.实现效果故障转移机制 一.简介 以提高应用系统的可靠性&#xff0c;尽可能地减少中断时间为目标&#xff0c;确保服务的连续性&#xff0c;达到高可用的容错效果。例如“故障切换”、“双机热备”、“多机热备”等都属于高可用集…

ceph集群的扩容缩容

文章目录 集群扩容添加osd使用ceph-deploy工具手动添加 添加节点新节点前期准备新节点安装ceph&#xff0c;出现版本冲突 ceph-deploy增加节点 集群缩容删除osd删除节点 添加monitor节点删除monitor节点使用ceph-deploy卸载集群 实验所用虚拟机均为Centos 7.6系统&#xff0c;8…

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

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

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

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

曲线救国 | 双非渣硕的秋招路

作者 | 带带大兄弟 面试锦囊之面经分享系列&#xff0c;持续更新中 欢迎后台回复"面试"加入讨论组交流噢 一篇旧文&#xff0c;可以参考~ 写在前面 双非渣硕&#xff0c;0实习&#xff0c;3篇水文&#xff0c;三个给老板当打工仔的nlp横向项目&#xff0c;八月份开…

文本三剑客之sed编辑器

sed 一、sed简介1.1 什么是sed&#xff1f;1.2 sed原理1.3 sed核心功能 二、sed命令格式详解2.1 命令格式2.2 常用选项2.3 sed脚本语法2.3.1 基本语法结构2.3.2 地址部分-----指定匹配范围2.3.3 命令部分-----要执行的命令 三、sed查找替换3.1 基本语法3.2 分组后向引用3.3 变量…

【面试八股文】每日一题:谈谈你对线程的理解

每日一题-Java核心-谈谈你对线程的理解【面试八股文】 Java线程是Java程序中的执行单元。一个Java程序可以同时运行多个线程&#xff0c;每个线程可以独立执行不同的任务。线程的执行是并发的&#xff0c;即多个线程可以同时执行。 1. 线程的特点 Java中的线程有如下的特点 轻…

[LeetCode - Python]844. 比较;含退格的字符串(Easy);415. 字符串相加(Easy)

1.题目 844. 比较含退格的字符串&#xff08;Easy&#xff09; 1.代码&#xff1a; class Solution:def backspaceCompare(self, s: str, t: str) -> bool:# 暴力法s list(s)t list(t)M 0N 0for i in range(len(s)):i -M if s[i] # :if i > 0 :s.pop(i)s.pop(i-…

LION AI 大模型落地,首搭星纪元 ES

自新能源汽车蓬勃发展以来&#xff0c;随着潮流不断进步和变革的“四大件”有着明显变化。其中有&#xff1a;平台、智能驾驶、配置、以及车机。方方面面都有着不同程度的革新。 而车机方面&#xff0c;从以前老旧的媒体机、 CD 机发展至如今具有拓展性、开放性、智能化的车机…

Docker部署php运行环境(php-fpm+nginx)

前言 如果使用docker去部署一套php的运行环境&#xff0c;我们需要构建出nginx、php-fpm两个容器&#xff0c;nginx通过fast_cgi协议去转发php-fpm中的端口&#xff0c;从而实现web server的搭建&#xff0c;接下来以php的laravel框架为演示例子。 部署php-fpm 第一步 编写ph…

一、数学建模之线性规划篇

1.定义 2.例题 3.使用软件及解题 一、定义 1.线性规划&#xff08;Linear Programming&#xff0c;简称LP&#xff09;是一种数学优化技术&#xff0c;线性规划作为运筹学的一个重要分支&#xff0c;专门研究在给定一组线性约束条件下&#xff0c;如何找到一个最优的决策&…

Prometheus 监控系统---你值得拥有

目录 一&#xff1a;Prometheus 1、Prometheus 概述 2、应用场景 3、Prometheus 的特点 4、Prometheus 的生态组件 &#xff08;1&#xff09;Prometheus server&#xff1a;服务核心组件 &#xff08;2&#xff09;Client Library: 客户端库 &#xff08;3&#xff0…

前端开发怎么解决前端安全性的问题? - 易智编译EaseEditing

前端安全性是保护前端应用程序免受恶意攻击和数据泄露的重要方面。以下是一些解决前端安全性问题的关键方法&#xff1a; 输入验证与过滤&#xff1a; 对所有用户输入进行验证和过滤&#xff0c;防止恶意用户通过注入攻击等手段破坏应用程序或获取敏感信息。 跨站点脚本&#…

安卓移动应用开发实训室建设方案

一 、系统概述 安卓移动应用开发作为新一代信息技术的重点和促进信息消费的核心产业&#xff0c;已成为我国转变信息服务业的发展新热点&#xff1a;成为信息通信领域发展最快、市场潜力最大的业务领域。互联网尤其是移动互联网&#xff0c;以其巨大的信息交换能力和快速渗透能…

k8s 自身原理之高可用

说到高可用&#xff0c;咱们在使用主机环境的时候&#xff08;非 k8s&#xff09;&#xff0c;咱做高可用有使用过这样的方式&#xff1a; 服务器做主备部署&#xff0c;当主节点和备节点同时存活的时候&#xff0c;只有主节点对外提供服务&#xff0c;备节点就等着主节点挂了…

logstash配置文件

input { kafka { topics > “xxxx” bootstrap_servers > “ip:port” auto_offset_reset > “xxxx” group_id > “xxxx” consumer_threads > 3 codec > “json” } } filter { grok { match > { “message” > ‘%{IP:client_ip} - - [%{HTTPDATE:…