今天我们讲一讲pgjdbc。pgjdbc是postgresql的JDBC接口。其网址是https://jdbc.postgresql.org/.是开源软件,我们可以轻松的查看其代码,理解jdbc的工作原理。


一. 源代码目录结构

pgjdbc的源码结构如下图:

那么我们来一一看看各个模块都是做什么的吧。

1 core

该目录是程序的核心模块目录。

这里实现了大部分pgjdbc的基类和接口,例如statement query log type command connection类等等;

并且在此基础上的Connection的V3协议(V2版本的协议在新版本里已删除);

2 data source

该模块实现的是jdbc的数据源模块。其中:

ds目录下提供基础的数据源支持;

xa目录下提供支持分布式事务的数据源;

3 common api

jdbc

jdbc2

jdbc3

Driver.java

这些目录下提供了共通的jdbc驱动接口。

4 extend api

这部分是postgresql独有的特殊命令和类型的支持。其中:

copy目录下的代码支持postgresql的COPY命令;

geometric目录下的代码 支持postgresql的集合类型;

fastpath目录下的代码是PostgreSQL提供一种快速路径接口来向服务器发送简单的函数调用。这个接口在某种程度上已被废弃,因为我们可以通过创建一个定义该函数调用的预备语句来达到类似或者更强大的功能;

largeobject目录下的代码提供对Postgresql的大对象数据类型的支持;

5 security api

ssl sspi gss这些很显然,这是对安全相关的认证的支持。

6 until

该目录下的代码提供一些工具库的实现。例如message类、 exception类

7 hostchooser

该目录下的代码提供了对连接字符串中targetServerType参数的支持。支持特定类型的host的选择(目前指定该参数为preferSlave有点bug)。

8 osgi

目录下的代码实现了OSGi(Open Service Gateway Initiative)技术是Java动态化模块化系统的一系列规范(老实说并不是太懂)。


二. 调用关系

调用关系的话,我们大家应该还是蛮熟悉的。不多说,举例子吧。

假设我们执行这样一个查询:

select * from hr.employees;

pgjdbc的工作时序大概下面这个样子(在网上找的图,侵删):

这里面唯一神秘的就是executeQuery()执行后,客服端和database的交互细节。下面我们简单的分析下这一段的协议流吧。


三. 协议流

PostgreSQL的客户端与服务端通过协议消息通信,下面以pgjdbc执行一个简单的SELECT为例说明

已定义以下的表。

create table ecpg_test(tint int, name text);
insert into ecpg_test values (12,'qwe');

执行的SELECT语句

select * from ecpg_test where tint =12

SELECT执行的流程

我们用一个java程序去连接postgresql。为了追踪log,我们如下设置:

1.客户端:连接字符串里面加上参数loggerLevel=TRACE来追踪这次连接以及查询

2.服务端:设置参数client_min_messages和log_min_messages为debug5(这里我为了log完整起见,其实没必要设置这么高)

运行完程序,log如下(为方便观察,我就摘抄了一部分,其它的我省略了):

.
.
.
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl execute
FINEST: simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@19d449fc, maxRows=0, fetchSize=0, flags=17
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST: FE=> Parse(stmt=null,query="select * from ecpg_test where tint =12",oids={})
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST: FE=> Bind(stmt=null,portal=null)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST: FE=> Describe(portal=null)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST: FE=> Execute(portal=null,limit=0)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl sendSync
FINEST: FE=> Sync
.
.
.
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl processResults
FINEST: <=BE ParseComplete [null]
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl processResults
FINEST: <=BE BindComplete [unnamed]
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl receiveFields
FINEST: <=BE RowDescription(2)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl receiveFields
FINEST: Field(tint,INT4,4,T)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl receiveFields
FINEST: Field(name,TEXT,65535,T)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl processResults
FINEST: <=BE DataRow(len=5)
11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl receiveCommandStatus
FINEST: <=BE CommandStatus(SELECT 1) 11 14, 2017 3:26:27 午後 org.postgresql.core.v3.QueryExecutorImpl receiveRFQ
FINEST: <=BE ReadyForQuery(I)
.
.
.
11 14, 2017 3:02:20 午後 org.postgresql.core.QueryExecutorBase close
FINEST: FE=> Terminate Process finished with exit code 0

可以看到,客户端在执行execute时,依次进行了sendParse、sendBind、sendDescribePortal、sendExecute、sendSync这些操作。

然后服务端对应这些操作分别对应给了处理和相应:ParseComplete、BindComplete、RowDescription、DataRow等等。

这些操作写在org.postgresql.core.v3包下的QueryExecutorImpl.java中。更详细一点的说,是在函数中:

private void sendOneQuery(SimpleQuery query, SimpleParameterList params, int maxRows,
int fetchSize, int flags)

其实这里有一个疑问,在sendOneQuery()函数里,上面所说的客户端和服务端操作是按照次序一一对应的执行的。手画一个草图比如:

  client  ------------------   ---  server
|sendParse() |
| --------------------------> |
| <------------------------- |
| ParseComplete |
|sendBind() |
| -------------------------> |
| <------------------------- |
| BindComplete |
.
.
.

也就是说,是有严格的次序关系的。可是我们看log可以发现,客户端的这些操作是一次性发到服务端,服务端也是处理完一次性发回的。那么为什么会不一致呢?

请教了朋友和同事,原来是:

为了优化网络传输。将多次发送的数据集中到一次发送,提高效率。

好的,今天就到这里。

引用:

http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=20726500&id=4150218

pgjdbc源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. JS类继承常用方式发展史

    JS类继承常用方式发展史 涉及知识点 构造函数方式继承 1-继承单个对象 1.1 多步走初始版 1.2 多步走优化版 1.3 Object.create()方式 2-继承多个对象 2.1 遍历 Obj ...

  2. 【转】NAS 黑群晖 配置完成(不含硬盘),NAS能做什么?

    在配黑群晖前,240元入手过一个艾美佳的NAS感受了下,功能倒还合适,就是配置太老,厂家固件也停止更新了,一直不太满意. 后来经常关注NAS1,发现现在X86的NAS也很好自己DIY了,就长草了,向女 ...

  3. Python数据可视化利器Matplotlib,绘图入门篇,Pyplot介绍

    Pyplot matplotlib.pyplot是一个命令型函数集合,它可以让我们像使用MATLAB一样使用matplotlib.pyplot中的每一个函数都会对画布图像作出相应的改变,如创建画布.在 ...

  4. html阶段测试

    1.简述src和href的区别? 2.在html页面的head中定义属性<meta http-equiv="X-UA-Compatible" content="IE ...

  5. 我的three.js学习记录(二)

    通过上一篇文章我的three.js学习记录(一)基本上是入门了three.js,但是这不够3D,这次我希望能把之前做的demo弄出来,然后通过例子来分析操作步骤. 1. 示例 上图是之前做的一个dem ...

  6. Hibernate 学习笔记 - 1

    一.Hibernate 的环境搭建.配置及 HelloWorld 1.在 Eclipse 中搭建 Hibernate 环境 下载 Hibernate 离线 jar 包(jbosstools-4.4.4 ...

  7. Python通过future处理并发

    future初识 通过下面脚本来对future进行一个初步了解:例子1:普通通过循环的方式 import os import time import sys import requests POP20 ...

  8. iOS自动化环境搭建——macaca

    macaca-java for ios 自动化环境搭建 基础原理解析:https://testerhome.com/topics/6608 一.环境搭建 1.安装eclipse; -----Java开 ...

  9. 当谈到 GitLab CI 的时候,我们该聊些什么(上篇)

    "微服务"这个概念近两年非常热,正在慢慢改变 DevOps 的思路.微服务架构把一个庞大的业务系统拆解开来,每一个组件变得更加独立自治.松耦合.但是,同时也伴随着部署单元粒度越来越 ...

  10. bootstrap学习之利用CSS属性pointer-events禁用表单控件

    参考链接: CSS3 pointer-events:none应用举例及扩展 首先pointer-events在除去SVG中的应用只有两个值:AUTO | NONE pointer-events:non ...