首页 > 数据库 >PgStatement的executeCachedSql(String sql, int flags, String @Nullable [] columnNames)方法的学习

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

时间:2024-08-02 17:07:26浏览次数:10  
标签:cachedQuery String Nullable columnNames queryExecutor 查询 sql

方法代码如下:

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类中找到该方法

@Override
  public 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 key
      key = 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)方法的作用,但对某些部分方法的并未追踪到底层,拟定另起文章对某些部分的底层方法进行学习分析。
随学随改

标签:cachedQuery,String,Nullable,columnNames,queryExecutor,查询,sql
From: https://www.cnblogs.com/bbban/p/18338783

相关文章

  • 一、MyString类的实现
    包括默认构造、有参构造、拷贝构造、拷贝赋值运算符、移动构造、移动赋值运算符及析构函数。classMyString{   MyString(constchar*buffer)//有参构造   {       length=strlen(buffer);       m_char=newchar[length+1];     ......
  • 24-7-31String类,StringBuffer类,StringBuilder类的详解与比较
    24-7-31String类,StringBuffer类,StringBuilder类的详解与比较文章目录24-7-31String类,StringBuffer类,StringBuilder类的详解与比较StringString的结构String的方法String对象的两种创建方法String的其他方法String练习StringExercise01StringExercise02StringExer......
  • 5.String类型的常见命令
    String类型,字符串类型,是redis中最简单的存储类型。根据字符串的格式不同分为三类:1.string普通字符串。2.int整型类型,可以自增,自减操作。3.float浮点类型,可以自增,自减操作。字符串最大空间不能超过512m。String类型数据的常见操作命令setkeyvalue添加或修改key-v......
  • 题解:CF559B Equivalent Strings
    CF559BEquivalentStrings题解题目描述吐槽一下,题目翻译有歧义。思路分析你会发现,当你需要判断字符串\(a,b\)是否等价时,如果长度为偶数,需要继续判断字符串\(a\)拆分的字串。所用知识s.substr(i,j)//在字符串s中,从位置i开始截取长度为j的字串参考代码#include<bits......
  • 【C++第十章】String
    【C++第十章】学习StringSTL介绍......
  • String的equals方法的实现原理以及==跟equals的区别
    publicclassStringTest05{publicstaticvoidmain(String[]args){Strings1="hello";Strings2=newString("hello");System.out.println(s1==s2);System.out.println(s1.equals(s2));}}此代码......
  • 如何解决toString检测?
      对于一些浏览器环境检测时,比较常见的toString方法检测,查看函数方法是否修改,从而来检测爬虫行为,以下是一种过toString检测的方法。1、修改toString方法。  代码如下:(()=>{"usestrict";const$toString=Function.toString();constmyFunction_toStrin......
  • CF873B Balanced Substring
    Abstract传送门本题定义平衡串为0和1数量相等的字符串,要求我们找出给定01串中含有的最大平衡串。Idea如果把1视为+1,0视为-1,那么一个01串是平衡串当且仅当其和值为0,那么问题就转变为寻找给定01串中和值为0的最长子段。首先做一个前缀和,a[i]表示前i项的......
  • JavaSE基础 (认识String类)
    一,什么是String类在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了Strin......
  • 学习笔记 String类案例练习 1.模拟用户登录 2.统计字符串英文字母大小写及数字个数
    目录案例一模拟用户登录需求:代码: 案例二统计字符串英文字母大小写及数字个数需求:代码:案例一模拟用户登录需求:已知正确的用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示代码:publicstaticvoidmain(String[]args){......