PgStatement的executeCachedSql(String sql, int flags, String @Nullable [] columnNames)方法的学习

news/2025/1/18 6:42:49/文章来源:https://www.cnblogs.com/bbban/p/18338783

方法代码如下:

private boolean executeCachedSql(String sql, int flags,String @Nullable [] columnNames) throws SQLException {//第一部分PreferQueryMode preferQueryMode = connection.getPreferQueryMode();boolean shouldUseParameterized = false;//第二部分QueryExecutor queryExecutor = connection.getQueryExecutor();//第三部分Object key = queryExecutor.createQueryKey(sql, replaceProcessingEnabled, shouldUseParameterized, columnNames);CachedQuery cachedQuery;//第四部分boolean shouldCache = preferQueryMode == PreferQueryMode.EXTENDED_CACHE_EVERYTHING;if (shouldCache) {cachedQuery = queryExecutor.borrowQueryByKey(key);} else {cachedQuery = queryExecutor.createQueryByKey(key);}//第五部分if (wantsGeneratedKeysOnce) {SqlCommand sqlCommand = cachedQuery.query.getSqlCommand();wantsGeneratedKeysOnce = sqlCommand != null && sqlCommand.isReturningKeywordPresent();}//第六部分boolean res;try {res = executeWithFlags(cachedQuery, flags);} finally {if (shouldCache) {queryExecutor.releaseQuery(cachedQuery);}}return res;}

对传入的参数进行分析,

  • sql显然是SQL语句;
  • flags根据名称只能推测是什么标志,待定;
  • columnNames为一个可为空的String数组,和列名有关,待定。

接下来,拟定分为六部分,对每一部分的代码进行分析。

第一部分

 PreferQueryMode preferQueryMode = connection.getPreferQueryMode();

该方法本质上为:

public PreferQueryMode getPreferQueryMode() {return queryExecutor.getPreferQueryMode();}

而queryExecutor为connection对象的一个属性

  /* Actual network handler */private final QueryExecutor queryExecutor;

查看QueryExecutor的注释

简单的总结:其抽象化了执行查询时与特定协议相关的细节,使得数据库连接可以通过单一的QueryExecutor实现来执行查询,而不必关心底层数据库协议或查询执行的具体细节。
而官方文档中有以下描述:

考虑到我们此次研究的方法,与之相关的点应该就是:提供创建Query对象的方法,并可以将该对象作为参数,执行查询语句。
查看Query类的注释

简单的总结:隐藏执行查询时所需的任何有关协议数据的细节,以便能够高效地执行查询。
不觉明历,看看官方文档

若有所得,在此基础上我们保持对该类的印象,回到第一部分的方法部分。
现在进度为queryExecutor.getPreferQueryMode(),按照当前的所得知的信息,Connection类中有一个QueryExecutor“类型”的属性,而QueryExecutor“类”中又有一个PreferQueryMode类的属性。
跳转到QueryExecutor接口的实现类QueryExecutorBase,找到preferQueryMode属性

我们发现,没有注释,继而跳到PreferQueryMode类的定义位置,查看其结构和注释

从其注释和明确的结构可知,PreferQueryMode类用于指定数据库的查询模式,Pgjdbc的查询模式如下:

  • SIMPLE("simple"):表示使用简单的查询执行模式,即直接以文本形式发送查询,不进行解析和绑定操作。
  • EXTENDED_FOR_PREPARED("extendedForPrepared"):表示仅对预处理语句使用扩展的查询执行模式,即使用bind/execute消息。
  • EXTENDED("extended"):表示对所有查询都使用扩展的查询执行模式。
  • EXTENDED_CACHE_EVERYTHING("extendedCacheEverything"):注释中未提到,从命名上看,它可能表示在扩展模式下缓存所有内容。

到此,我们已经知道了第一部分的作用,即获取当前连接指定的查询模式

第二部分

QueryExecutor queryExecutor = connection.getQueryExecutor();

该方法即获得该connection实例的queryExecutor属性,关于QueryExecutor在第一部分也有了提及,此处不再重复。
到此,我们知道了第二部分的作用,即获取当前连接的queryExecutor属性

第三部分

Object key = queryExecutor.createQueryKey(sql, replaceProcessingEnabled, shouldUseParameterized, columnNames);

首先,先分析一下传入的参数,sql、columnNames和shouldUseParameterized均在方法中提及,唯有replaceProcessingEnabled为方法所在类的属性,如下:

该属性未发现注释,字面意思理解为是否启用替换处理,结合上下文猜测应该为对sql语句是否启用替换处理,暂时如此推测,继续向下处理。
QueryExecutorBase类中找到该方法

@Overridepublic final Object createQueryKey(String sql, boolean escapeProcessing,boolean isParameterized, String @Nullable ... columnNames) {Object key;if (columnNames == null || columnNames.length != 0) {// Null means "return whatever sensible columns are" (e.g. primary key, or serial, or something like that)key = new QueryWithReturningColumnsKey(sql, isParameterized, escapeProcessing, columnNames);} else if (isParameterized) {// If no generated columns requested, just use the SQL as a cache keykey = sql;} else {key = new BaseQueryKey(sql, false, escapeProcessing);}return key;}

参数对应关系:sql同上,escapeProcessing对应是否启用替换处理,isParameterized对应是否启动参数化,columnNames未知。
结合注释推测,对传入的columnNames数组有了推测,其应该为select语句查询的字段名,根据本方法的判断逻辑,该数组应该是有三种状态:

null,表示全查
有限个字段名,查这些字段
String[0],表示该语句并非查询语句

因而,我们对该方法有了大致推测:

sql为SQL语句;
escapeProcessing对应是否启用替换处理(待定);
isParameterized对应是否启动参数化;
columnNames为若该sql为select语句时查询的字段名列表;
本方法应为:为该sql语句新建查询键。此处,将自学查询建的知识,对该部分进行补充。

对应判断逻辑为:

若columnNames为null或有值,则新建一个有返回值的查询建。
否则,若启动参数化,则使用该sql语句做查询键,
若未启动参数化,则新建一个Base查询键

总结,该部分的作用为为该sql语句新建查询键,该查询建默认启动参数化

第四部分

boolean shouldCache = preferQueryMode == PreferQueryMode.EXTENDED_CACHE_EVERYTHING;if (shouldCache) {cachedQuery = queryExecutor.borrowQueryByKey(key);} else {cachedQuery = queryExecutor.createQueryByKey(key);}

该部分的逻辑很容易理解,若该连接指定的查询模式为EXTENDED_CACHE_EVERYTHING,则根据查询键尝试从缓存中获得该查询,否则新建一个查询。
此部分对于该模式的运作不甚了解,猜测应该是在新建的缓存查询是共享的,能根据查询建找到就不要选择新建,不慎了解,不多言,待补充
通过查看该CachedQuery类的注释可知,其存储解析后的JDBC查询信息,其主要目的在于通过java.sql.Connection#prepareStatement(String)方法多次执行相同查询时,减少解析的开销。

总之,该部分的作用是:根据该查询键获得一个CachedQuery类的实例

第五部分

   if (wantsGeneratedKeysOnce) {SqlCommand sqlCommand = cachedQuery.query.getSqlCommand();wantsGeneratedKeysOnce = sqlCommand != null && sqlCommand.isReturningKeywordPresent();}

wantsGeneratedKeysOnce是PgStatement类的一个属性,其注释说明,其用来标记调用 execute 或 executeUpdate 方法时,调用者是否希望获取这次执行所生成的键。由此描述可知,该属性与执行的sql语句类型有关。
如果当前sql想要获得这次执行所生成的键,则调用cachedQuery.query.getSqlCommand()方法获得sqlCommand,若其非空且包含对应关键词,则更新wantsGeneratedKeysOnce。获得的qlCommand并未在之后的部分使用。
总之,该部分的作用为:更新wantsGeneratedKeysOnce属性

第六部分

    boolean res;try {res = executeWithFlags(cachedQuery, flags);} finally {if (shouldCache) {queryExecutor.releaseQuery(cachedQuery);}}

该部分的主要部分为:res = executeWithFlags(cachedQuery, flags);,很明显该方法为执行查询,但至此我们对flags参数的含义和res的含义未加确定,因而追踪一步:

显然在此,flags的实际应用形式为二级制,每一位作为一个标志,每一位都能存储一条二元信息,其可以看作是一个二元数组的形式;res则为指示是否有返回值。因为该方法调用层次过多,故不在此详述
总结,本部分作用为:实现查询,并返回是否有返回结果的判断

总结

参数意义

String sql : sql语句
int flags:一个记录标志信息的二进制数组
String @Nullable [] columnNames :存储查询字段名的数组,如非查询语句,其为String[0],需要注意的是,null代表全体字段名,而不是异常。

结论

本文详细分析了PgStatement的executeCachedSql(String sql, int flags, String @Nullable [] columnNames)方法的作用,但对某些部分方法的并未追踪到底层,拟定另起文章对某些部分的底层方法进行学习分析。
随学随改

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

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

相关文章

初识RestAssured

1、接口测试的本质 不在于创造,在别人写好的情况下去调用--发起请求,校验结果 2、接口测试的四要素URL地址 请求方式 请求参数 返回值3、RestAssured介绍 RestAssured的依赖导入点击查看代码 <dependencies> <!-- Rest-Assured核心库 --> <dependency> …

ximo基础脱壳教程的脱壳学习记录

ximo基础脱壳教程的脱壳学习记录 之前遇到壳直接脚本自动化处理了,现在初步学习一下手脱壳。(中间一直用的x32dbg,后来有些壳换od脱了) 参考教程https://www.52pojie.cn/thread-582852-1-1.html 1、手脱UPX壳 查壳方法1:单步跟踪 就是一直单步走,如果是向下跳转就跳,如果…

.net 8 应用在docker容器中创建失败 Failed to create CoreCLR, HRESULT: 0x80070008

在UAT环境中docker容器里部署.net8 应用没问题,在dev环境docker run 启动失败,并报错 Failed to create CoreCLR, HRESULT: 0x80070008以下文章解决了我遇到的问题,感谢 https://www.cnblogs.com/cyq1162/p/17981333 处理办法 增加--security-opt seccomp=unconfined docker…

【AI冰封挑战】搭档函数计算,“冰”封你的夏日记忆

在 AI 绘画领域,Stable Diffusion、 WebUI、Midjourney 等工具各领风骚,但 ComfyUI 以其独特的自动化工作流机制,自问世以来便迅速崭露头角,成为众多应用开发者和艺术创作者的新宠。它不仅革新了 AI 生图的创作流程,更以高效的自动化水平,为AI绘画领域开辟了全新的篇章。…

IT事件经理在数字企业中的角色和责任

什么是IT事件经理? IT事件经理有时也被称为事件指挥官,他们承担着管理组织事件响应的总体责任,从委派各种事件响应任务到与每个利益相关者进行沟通和协调。 示例:当一个全球性的电子商务平台在一次销售活动中流量激增,数以百万计的用户涌入网站时,不可预见的技术故障开始…

maven项目pom文件查看架包依赖处理架包冲突问题

在运行maven项目的时候由于依赖冲突出现如下问题 项目中依赖了多个不同版本的slf4j类库,我们可以使用dependency:tree命令: 找到冲突的依赖,向上找到引入依赖的根源,在对应的pom文件里,添加 <exclusions> 标签即可<dependency><groupId>com.baidu.ai…

Tarjan算法和连通性相关(二)

上一篇博客我们介绍了强连通分量,本文我们继续学习与连通性有关的一些概念 割点什么是割点?对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点 我们画个图理解一下:在这个图中,如果我们把 3 这个点给删除掉,那么这张图就会被拆…

Kotlin 字符串教程:深入理解与使用技巧

Kotlin中的字符串用于存储文本,定义时使用双引号包围字符序列,如`var greeting = "Hello"`。Kotlin能自动推断变量类型,但在未初始化时需显式指定类型,如`var name: String`。可通过索引访问字符串元素,如`txt[0]`获取首字符。字符串作为对象,拥有属性和方法,…

Zabbix搭建

目录zabbix搭建1. 前置环境准备1.1 搭建LNMP2. zabbix准备工作2.1 安装php模块以及编译所需工具2.2 修改php配置2.3 编译安装zabbix2.3.1 下载tar包2.3.2 解压2.3.3 创建用户/组2.3.4 开始安装2.3.5 配置数据库3. 配置zabbix3.1 修改配置文件3.2 Web界面部署4. 安装agent5. 添加…

苍穹外卖项目--学习笔记

苍穹外卖学习文档 软件开发整体介绍 软件开发流程 需求分析 需求规格说明书、产品原型 设计 UI设计、数据库设计、接口设计 编码 项目代码、单元测试 测试 测试用例、测试报告 上线运维 软件环境安装、配置 角色分工项目经理 对整体项目负责,任务分配、把控进度产品经理 进行需…

无缝融入,即刻智能[1]:MaxKB知识库问答系统,零编码嵌入第三方业务系统,定制专属智能方案,用户满意度飙升

无缝融入,即刻智能[1]:MaxKB知识库问答系统,零编码嵌入第三方业务系统,定制专属智能方案,用户满意度飙升无缝融入,即刻智能[1]:MaxKB知识库问答系统,零编码嵌入第三方业务系统,定制专属智能方案,用户满意度飙升 1.简介 MaxKB(Max Knowledge Base)是一款基于 LLM 大语…

魔鬼训练营-第四章学习笔记(上)

4.1.5 基于Metasploit框架的Web应用渗透技术 代码清单4-1 Metasploit下初始化wmap使用wmap进行扫描wmap官网有介绍,介绍得也比书中详细,可在后续练习中测试该工具功能是否仍然强大代码清单4-8 直接照搬书中,按照其代码复现似乎有点问题,需要另想办法复现wXf 似乎已失效,后…