今天我们讲一讲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. Win下安装虚拟机(Linux)

    **********************win下体验linux**************************************By熟知宇某 一.先说说win10和win8系统下的hyp ...

  2. 基于LoadRunner11,以wifi热点方式录制APP脚本简单指导

    本想详细写下操作过程,但并不觉着十分必要,通过baidu或我要自学网均能找到相关资料,所以详细操作过程不再赘述,只是把过程中遇到的问题说明下解释下,让大家“录制APP”的路更平坦! 1.如何使用Loa ...

  3. ubuntu中安装ftp服务器

    1. 实验环境 ubuntu14.04 2.vsftpd介绍 vsftpd 是“very secure FTP daemon”的缩写,是一款在Linux发行版中最受推崇的FTP服务器程序,安全性是它的 ...

  4. 安装Extended WPF Toolkit

    Extended WPF Toolkit 可以说是WPF Toolkit 的一个补充,也包含了许多WPF 控件供开发者使用.本篇将介绍Extended WPF Toolkit 1.4.0 中新增的一些 ...

  5. JAVA几种常见的编码格式(转)

    简介 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多.本文将向你详细介绍 Java 中编码问题出现的根本原因,你将了解到:Jav ...

  6. iOS10新特性之SiriKit

    在6月14日凌晨的WWDC2016大会上,苹果提出iOS10是一次里程碑并且推出了十个新特性,大部分的特性是基于iPhone自身的原生应用的更新,具体的特性笔者不在这里再次叙述,请看客们移步WWDC2 ...

  7. win10 uwp 设置启动窗口大小 获取窗口大小

    本文主要说如何设置我们窗口的启动大小,UWP启动窗口大小. 设置启动窗口 设置窗口大小 ApplicationView.PreferredLaunchViewSize = new Size(1000, ...

  8. 二:Linux 的基本命令、VI编辑器、Linux中软件安装

    Linux 的基本命令 1. 文件操作 a) Windows 是多根的文件系统,物理上是 1 到多块硬盘,逻辑上分为 C.D.E--盘, 每个盘都是一棵树.Linux 是单根的文件系统,不分 CDE ...

  9. MySQL比like语句更高效的写法locate position instr find_in_set

    使用内部函数instr,可代替传统的like方式查询,并且速度更快. instr函数,第一个参数是字段,第二个参数是要查询的串,返回串的位置,第一个是1,如果没找到就是0. 例如, select na ...

  10. LINUX 笔记-iproute2 命令

    一.IP 地址管理 1.显示 IP 地址 ip addr show [dev eth0] 2.增加删除 IP 地址 ip addr add 192.0.2.1/24 dev eth0 ip addr ...