pgjdbc与PostgreSQL数据库的通信机制
pgjdbc与PostgreSQL数据库的通信机制
PostgreSQL JDBC驱动(pgjdbc)与PostgreSQL数据库服务器之间的通信采用基于TCP/IP的socket连接,使用的是PostgreSQL专有的前端/后端协议。从提供的代码上下文看,pgjdbc实现的是该协议的v3版本(QueryExecutorImpl.java在v3包下)。
通信方式与协议概述
通信方式
- 基于TCP/IP的socket通信
- 全双工通信:客户端和服务器可以同时发送和接收消息
- 消息驱动:通过交换格式化的二进制消息进行通信
协议版本
// org.postgresql.core.v3.QueryExecutorImpl.java
@Override
public int getProtocolVersion() {
return 3; // 协议版本3
}
PostgreSQL前端/后端协议v3是从PostgreSQL 7.4版本引入的,现在的PostgreSQL服务器普遍支持此版本,也是pgjdbc默认使用的协议版本。
协议特点
1. 消息结构
每个消息都有特定的格式,通常包括:
- 单字节消息类型标识符
- 4字节长度字段(包括长度本身)
- 消息内容
// 发送简单查询消息示例
pgStream.sendChar('Q'); // 消息类型'Q'表示简单查询
pgStream.sendInteger4(length); // 消息长度
pgStream.sendString(sql); // SQL文本
2. 两种查询模式
协议支持两种主要的查询执行模式:
简单查询模式
// 在QueryExecutorImpl.java中
if ((flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0) {
// 简单查询模式
pgStream.sendChar('Q'); // 简单查询消息类型
pgStream.sendString(query.toString(parameters)); // 完整SQL语句
}
这种模式简单直接,一条消息包含整个SQL语句。
扩展查询模式
// 在QueryExecutorImpl.java中
else {
// 扩展查询模式,分多步执行
sendParse(query, parameters); // 解析阶段
sendBind(query, parameters); // 绑定阶段
sendExecute(); // 执行阶段
sendSync(); // 同步
}
扩展查询模式将SQL执行拆分为多个步骤,支持预编译和参数绑定。
3. 二进制数据支持
协议支持文本和二进制两种数据格式,可以大幅提高性能:
// 在PgConnection.java中
public boolean binaryTransferSend(int oid) {
return queryExecutor.useBinarySendForOid(oid);
}
4. 异步操作支持
协议支持非阻塞操作,允许取消正在执行的查询:
// 在QueryExecutorImpl.java中
@Override
public void sendQueryCancel() throws SQLException {
PGStream cancelStream = null;
try {
// 创建取消请求
cancelStream = cancelQuery();
} finally {
if (cancelStream != null) {
try {
cancelStream.close();
} catch (IOException e) {
/* ignore */
}
}
}
}
5. 服务器端预编译
支持将SQL语句在服务器端预编译,提高重复执行的性能:
// 在QueryExecutorImpl.java中
private void sendParse(Query query, V3ParameterList parameters) throws IOException {
// 给语句一个名称,以便重用
String statementName = query.getStatementName();
// 发送Parse消息
pgStream.sendChar('P');
pgStream.sendString(statementName);
pgStream.sendString(query.getNativeSql());
// 参数类型信息
pgStream.sendInteger2(parameters.getTypeOIDs().length);
for (int i = 0; i < parameters.getTypeOIDs().length; i++) {
pgStream.sendInteger4(parameters.getTypeOIDs()[i]);
}
}
主要消息类型
客户端到服务器的消息
- Q: 简单查询
- P: 解析(Parse)
- B: 绑定(Bind)
- E: 执行(Execute)
- D: 描述(Describe)
- S: 同步(Sync)
- X: 终止(Terminate)
服务器到客户端的消息
- R: 认证请求
- T: 行描述(Row Description)
- D: 数据行(Data Row)
- C: 命令完成(Command Complete)
- E: 错误(Error)
- N: 通知(Notice)
- Z: 准备接收查询(Ready For Query)
错误和异常处理
协议提供了详细的错误报告机制:
// 在QueryExecutorImpl.java中
private SQLException receiveErrorResponse() throws IOException {
// 读取错误字段
ServerErrorMessage serverError = new ServerErrorMessage(pgStream);
// 转换为SQLException
return new PSQLException(serverError);
}
总结
PostgreSQL的前端/后端通信协议具有以下优势:
- 高效:支持二进制数据传输和服务器端预编译
- 灵活:提供简单和扩展两种查询模式
- 强大:支持异步操作、批处理和事务管理
- 类型安全:提供详细的类型系统和类型转换
- 详细的错误报告:提供结构化的错误信息
pgjdbc驱动的核心任务就是封装这一复杂协议,为Java应用程序提供符合JDBC规范的简洁接口,同时充分利用PostgreSQL特有的功能和性能优化。
License:
CC BY 4.0