
libpqxx 7.7.3 实践指南用 C 编写 PostgreSQL 客户端从构建、连接字符串到事务编程【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOnelibpqxx 是 PostgreSQL 官方 C 接口 libpq 之上的一层现代 C 封装把数据库连接、事务、查询结果封装成connection、work、result等类型安全的类让 C 开发者用接近原生 C 的风格操作 PostgreSQL。本文以仓库内 ext/libpqxx-7.7.3/README.md 为骨架完整覆盖从源码构建CMake 与 configure 双路径、连接字符串配置、第一个程序的编写、到与 libpq 的链接方式并结合本仓库 ZeroTier Central Controller 的 PostgreSQL 存储后端源码展示 libpqxx 在真实项目中的落地用法。读完本文你将具备独立编译 libpqxx、写出健壮的 C/PostgreSQL 程序并理解事务、流式读取、LISTEN/NOTIFY 等高级用法在工程中的实际形态。libpqxx 是什么libpqxx 是面向 PostgreSQL 数据库管理系统的 C API其核心设计是构建在 PostgreSQL 标准 C APIlibpq之上——正如 README 所言“The library builds on top of PostgreSQLs standard C API, libpq, though your code wont notice.” 也就是说你的程序不需要直接接触 libpq 的回调、结构体和错误码而是通过 libpqxx 提供的类来编写更直观、更不容易出错的 C 代码。编译 libpqxx 本身要求系统已安装 PostgreSQL或者至少安装了客户端开发所需的 C 头文件与库即 libpq 的开发包例如 Debian/Ubuntu 下的libpq-dev。版本与升级要点7.x 用户必读README 明确给出了两条与语言标准强相关的升级红线7.x 系列要求至少 C17如果编译器过旧需要先升级。8.x 系列则至少需要 C20。本仓库内置的 CMakeLists.txt 印证了这一要求if(NOT ${CMAKE_CXX_STANDARD}) set(CMAKE_CXX_STANDARD 17) endif()即默认以 C17 编译且CMAKE_CXX_STANDARD_REQUIRED ON强制满足该标准。7.0 在少数低频使用的 API 上引入了破坏性变更从旧版本升级时需要特别注意只剩单一的connection类且连接是立即建立的不再有延迟建立连接的变体不再支持自定义connection子类连接一旦关闭就不能再重新激活没有 reconnect 机制定义字符串转换string conversion的 API 发生了变化。如果你自定义了类型转换7.1 还要求在nullnesstraits 中额外提供一个字段。本仓库 Central Controller 的源码恰好为上述“连接关闭后无法重新激活”这一特性提供了工程佐证在 nonfree/controller/PostgreSQL.hpp 中PostgresConnection::alive()通过c-is_open()判断连接是否仍然可用其注释明确写道 “pqxx 7 has no reconnect”当后端连接失效服务器重启、AlloyDB 维护、网络中断时连接池会直接丢弃这条死连接并新建一条而不是尝试复活它。如何构建 libpqxxlibpqxx 提供两种命令行构建方式README 与两份详细构建文档分别展开CMake任何支持 CMake 的系统均可用详见 ext/libpqxx-7.7.3/BUILDING-cmake.mdconfigure 脚本适用于 Unix 系系统包括 GNU/Linux、macOS、BSD 家族、AIX、HP-UX、Irix、Solaris 等在 Windows 上也可以通过 WSL、Cygwin 或 MinGW 这类 Unix 环境使用详见 ext/libpqxx-7.7.3/BUILDING-configure.md。无论哪种方式前提都是先安装 PostgreSQL 客户端开发包libpq 的头文件与库。方式一CMake 构建快速开始从 libpqxx 源码树根目录执行三步即可完成配置、编译、安装cmake . cmake --build . cmake --install .整个流程分为五个阶段Configure配置→ Compile编译→ Test测试可选→ Install安装→ Use使用。Configure 阶段运行cmake时它会自动探测 libpq 及其头文件的位置、编译器支持的 C 特性、需要的编译选项并为你的构建工具生成配置make的 Makefile、MSVC 的.sln解决方案文件等。这里用$SRC表示源码目录、$BUILD表示构建目录cd $BUILD cmake $SRC常用 CMake 选项速查表来自 BUILDING-cmake.md选项作用-DSKIP_BUILD_TESTon跳过编译 libpqxx 的测试套件-DBUILD_SHARED_LIBSon构建共享库-DBUILD_SHARED_LIBSoff构建静态库-DBUILD_DOCon构建文档需要 Doxygen 等工具-DINSTALL_TESTon安装测试执行器二进制构建方式建议Windows 上推荐构建共享库并与应用程序一起打包其他平台推荐静态库。选择构建生成器Generator可以用-G指定底层构建工具cmake -G Unix Makefiles # 强制使用 make cmake -G Ninja # 使用 ninja让 CMake 找到 libpqCMake 通过find_package自动定位 libpq如果失败或想指向非标准位置有两种覆盖方式逐项指定$DIR为对应目录-DPostgreSQL_TYPE_INCLUDE_DIR$DIR-DPostgreSQL_INCLUDE_DIR$DIR-DPostgreSQL_LIBRARY_DIR$DIR更简单的整体指定需 CMake 3.12-DPostgreSQL_ROOT$DIR直接指向完整的 PostgreSQL 构建树。Compile、Test、Install 阶段编译$BUILD为构建目录cmake --build $BUILD等价的手工方式Unix Makefiles 用make、Ninja 用ninja、Visual Studio 用msbuild libpqxx.sln。Make 系工具可用-j 16之类参数并行加速Ninja 会自动并行不需要也不应手动指定。运行测试套件test/runner安装到默认位置或自定义位置cmake --install $BUILD # 安装到系统默认位置 cmake --install $BUILD --prefix $DEST # 安装到 $DEST如 /usr/local 或 D:\Software在 CMake 项目中集成 libpqxx其他 CMake 项目可以把 libpqxx 作为子目录引入。BUILDING-cmake.md 给出了一份可直接套用的配置设置PostgreSQL_FOUND为 true 并外部传入 PostgreSQL 头文件目录从而绕过 FindLibrary 探测set(libpqxxdir libpqxx-${LIBVERSION}) # LIBVERSION 自行设定 set(SKIP_BUILD_TEST on) set(BUILD_SHARED_LIBS OFF) # 用这个替代 FindLibraryPostgresSQL_INCLUDE_DIRS 在外部设置 set(PostgreSQL_FOUND true) set(PostgresSQL_INCLUDE_DIR ${PostgresSQL_INCLUDE_DIRS}) set(PostgresSQL_TYPE_INCLUDE_DIR ${PostgresSQL_INCLUDE_DIRS}) add_subdirectory(${libpqxxdir})安装后CMakeLists.txt 会生成libpqxx-config.cmake与版本文件并导出带libpqxx::命名空间的 CMake targets便于下游项目用find_package(libpqxx)直接使用。方式二configure 脚本构建快速开始./configure make sudo make installConfigure 阶段常用选项速查表选项作用--disable-documentation跳过文档构建CXXFLAGS-O0关闭优化代码更慢但构建更快CXXFLAGS-O3开启更强优化代码更快但构建更慢CXXclang使用 clang 编译--enable-maintainer-mode让编译器对代码更严格更挑剔--enable-audit开启昂贵的运行时检查用于调试--with-postgres-lib$DIR在$DIR查找 libpq 库--with-postgres-include$DIR在$DIR查找 libpq 头文件--prefix$PATH安装到$PATH--enable-shared/--disable-shared启用/禁用共享库编译--enable-static/--disable-static启用/禁用静态库编译--help查看更多选项两个实用组合示例追求快速构建可用./configure --disable-documentation CXXFLAGS-O0想要最大程度暴露代码问题可用./configure --enable-maintainer-mode --enable-audit CXXFLAGS-O3-O3会促使编译器做额外分析顺带对未使用变量等毛病给出警告。configure 如何找到 libpqconfigure按三种途径定位 libpq 的头文件与库询问常用的pkg-config工具若已安装询问 PostgreSQL 已废弃的pg_config工具若已安装通过显式命令行选项--with-postgres-lib库二进制与--with-postgres-include头文件。跨平台交叉编译目标 CPU 架构与本机不同或使用非标准位置安装的 libpq 时应使用显式选项。configure 脚本的来源configure由 GNU autoconf 及相关工具生成仓库内的 autogen.sh 可以重新生成它真正维护的源码是更高层的 configure.ac其中编写了对 libpq 和编译器特性的检查逻辑。configure本身是自动生成的巨型脚本、难以阅读若想深入理解构建探测逻辑应阅读configure.ac而不是调试configure。Compile、Test、Install 阶段编译默认单进程务必用-j并行加速make -j8 # 粗略按 CPU 核数设置 make -j$(nproc) # 有 nproc 工具时自动按核数并行运行测试套件make check make check -j$(nproc)安装与卸载保留构建树将来可执行make uninstall撤销安装make install make uninstall测试套件的数据库配置libpqxx 自带完整测试套件但它需要一个允许免密登录、无额外参数的测试数据库测试会创建和删除大量以pqxx前缀命名的表因此尽量不要与业务数据混用。若测试数据库需要密码、位于其他机器或非默认端口可通过以下环境变量配置这些变量只设置默认值不会覆盖程序内部显式传入的参数PGHOST— 数据库 socket 的 IP 地址Unix 域 socket 则为文件系统绝对路径PGPORT— 连接数据库的 TCP 端口号PGDATABASE— 要连接的数据库名PGUSER— 登录数据库的用户名PGPASSWORD— 对应用户的密码密码安全提醒shell 可能会记录输入过的命令环境变量也可能被系统上其他用户看到因此尽量不要在命令行直接设置密码条件允许时优先依赖 PostgreSQL 的 peer authentication它既更安全也更方便。用 libpqxx 编写你的第一个程序核心类与头文件包含风格第一个程序只需要两个核心类connection数据库连接定义在 include/pqxx/connection.hxxworktransaction的便捷别名符合 include/pqxx/transaction_base.hxx 定义的接口。注意*.hxx并不是你在程序中直接 include 的文件。程序应包含不带后缀的版本如pqxx/connection它们会替你包含对应的.hxx实现文件。这样既保持了标准 C 的包含风格类似iostream编辑器又能把无后缀文件识别为 C 代码。此外查询结果类型resultinclude/pqxx/result.hxx也是高频类。从 include/pqxx 目录看libpqxx 还提供了丰富的类型与功能模块transaction/nontransaction/robusttransaction/subtransaction多种事务类型、row/field行列访问、stream_from/stream_to流式读写、prepared_statement预处理语句、pipeline管道批处理、blob/largeobject大对象、notificationLISTEN/NOTIFY、array/composite/range复合类型、strconv字符串转换等。编程模型典型流程是基于连接字符串创建connection→ 在该连接上下文里创建work事务 → 在work上执行一条或多条查询并得到result对象。result是行row的容器每一行都可以当作字符串数组看待——每个字段对应一个元素就这么简单。完整示例程序含错误处理README 给出的经典示例直接可编译运行假设数据库中存在employee表#include iostream #include pqxx/pqxx int main() { try { // Connect to the database. pqxx::connection C; std::cout Connected to C.dbname() \n; // Start a transaction. pqxx::work W{C}; // Perform a query and retrieve all results. pqxx::result R{W.exec(SELECT name FROM employee)}; // Iterate over results. std::cout Found R.size() employees:\n; for (auto row: R) std::cout row[0].c_str() \n; // Perform a query and check that it returns no result. std::cout Doubling all employees salaries...\n; W.exec0(UPDATE employee SET salary salary*2); // Commit the transaction. std::cout Making changes definite: ; W.commit(); std::cout OK.\n; } catch (std::exception const e) { std::cerr e.what() \n; return 1; } return 0; }示例中值得留意的细节pqxx::connection C;不带参数时使用默认连接参数见下文连接字符串pqxx::work W{C};开启事务所有查询挂在该事务上W.exec(...)执行查询并返回完整结果集W.exec0(...)执行期望不返回行的语句如 UPDATE若意外返回结果会抛异常显式调用W.commit()提交事务若在提交前抛出异常离开作用域事务会回滚整个程序用try/catch(std::exception)包裹任何数据库错误都会以异常形式暴露——这是 libpqxx 相比裸 libpq 最大的便利之一错误处理是异常驱动的。连接字符串连接参数与优先级规则Postgres 连接字符串用来说明连接哪台服务器、以哪个用户名、用哪个密码等。其格式由 libpqPostgreSQL 的 C 客户端接口定义也可以通过设置环境变量来提供默认值与 psql 手册中的定义一致libpqxx 程序遵循相同的规则。连接字符串由空格分隔的属性值对组成例如userjohn password1x2y3z4。README 列出的有效属性包括属性含义host要连接的服务器名称或本地 Unix 域 socket 的完整文件路径以/开头。默认/tmp。等价于且覆盖环境变量PGHOSThostaddr要连接的服务器的 IP 地址与host互斥port服务器主机上要连接的端口号Unix 域连接时为 socket 文件名的扩展。等价于且覆盖环境变量PGPORTdbname要连接的数据库名。一台服务器可承载多个数据库。默认与当前用户名同名。等价于且覆盖环境变量PGDATABASEuser连接使用的用户名。默认是当前系统用户名注意 PostgreSQL 用户与系统用户并非同一概念requiressl若设为 1强制要求加密 SSL 连接无法建立 SSL 连接则失败关于优先级README 明确了一条逐属性的规则连接字符串中的设置覆盖环境变量环境变量又覆盖默认值。因此你只需要为那些要求非默认值的属性做设置。同时需要说明的是上述清单并非完整权威列表例如较新版本的 libpq 文档推荐用sslmode等更细粒度的 SSL 参数权威定义请以 PostgreSQL 官方 libpq 文档为准。链接 libpqxx 到你的程序链接最终程序时需要同时链接 C 层的 libpq 库和 C 层的 libpqxx 库。多数 Unix 风格编译器使用-lpqxx -lpq两个库都必须位于链接器搜索路径中如果程序在运行时使用动态库这些动态库还必须位于加载器loader能找到的位置。常见问题与解法当系统上部分/错误地安装了多个 libpqxx 版本时上述语法可能引发大量链接错误。此时可以去掉-lpqxx改为直接给出 libpqxx 库二进制文件的完整路径例如/usr/local/pqxx/lib/libpqxx.a。这样可以确保链接器使用指定精确版本的库而不是系统中其他位置找到的版本彻底消除版本歧义。源码级纵深libpqxx 在 ZeroTier Central Controller 中的真实用法本仓库的 ZeroTier Central Controller集中控制器在启用ZT_CONTROLLER_USE_LIBPQ时以 libpqxx 作为 PostgreSQL 存储后端的唯一 C 访问层。阅读这些真实源码能帮助你理解 libpqxx 各 API 的工程化组合方式。连接管理与连接池在 nonfree/controller/PostgreSQL.hpp 中PostgresConnection持有一个std::shared_ptrpqxx::connectionPostgresConnFactory::create()用连接字符串构造连接c-c std::make_sharedpqxx::connection(m_connString);结合 ConnectionPool.hpp 的连接池alive()用is_open()判定连接是否可用死连接会被池丢弃并重建——这正对应前文“pqxx 7 无 reconnect”的约束。事务与查询work result row在 nonfree/controller/CentralDB.cpp 中大量出现pqxx::work w(*c-c);与w.exec(...)的组合例如用pqxx::row承接单行结果_getNetwork、_getNetworkMember辅助函数均以pqxx::work作为事务参数用pqxx::result承接多行结果并配合 INSERT/SELECT 语句完成 SSO 过期时间、网络与成员配置的读写。流式读取stream_from对于大批量初始化场景如启动时加载全部网络配置CentralDB 使用pqxx::stream_from::query(w, qbuf)流式读取将每一行解析进std::tuplestd::string, std::optionalstd::string, ...——std::optional完美映射数据库 NULL这是 C17 与 libpqxx 7.x 结合的典型写法见 CentralDB.cpp 第 672-693 行附近的初始化逻辑。相比一次性拉取全部result流式读取在数据量大时内存占用更低。LISTEN/NOTIFYnotification_receiver 与 await_notification控制器需要实时感知数据库中的变更为此在 nonfree/controller/PostgreSQL.hpp 中派生了多个pqxx::notification_receiver子类MemberNotificationReceiver、NetworkNotificationReceiver、通用的_notificationReceiver在指定 channel 上注册回调随后由监听线程循环调用c-await_notification(timeout, 0)等待消息见 PostgreSQL.cpp 的listen()循环。这是一个值得记住的工程细节onNotification回调中解析非法 payload 时可能抛异常异常会从await_notification逃逸出来libpqxx 会把异常传播到监听线程若不捕获会触发std::terminate拖垮整个控制器。因此源码在监听循环外围捕获全部异常、丢弃死连接、退避 1 秒后重连防止数据库不可达时产生热循环。构建集成控制器侧以pqxx为链接目标见 nonfree/controller/CMakeLists.txt依赖声明在 nonfree/controller/README_CENTRAL_CONTROLLER.mdDebian trixie 及更新系统上安装libpqxx-dev libpq-devmacOS 上通过brew bundleBrewfile 中包含 libpqxx安装macOS 构建时还需在CMAKE_PREFIX_PATH中追加 Homebrew 的 keg-only libpq 前缀。文档与进一步阅读构建 libpqxx 时若安装了相应工具会在doc/目录生成基于 include/pqxx 头文件与include/pqxx/doc/文本的 HTML 文档。本仓库内可直接查阅的资料还包括构建与安装 BUILDING-cmake.mdCMake 路径、BUILDING-configure.mdconfigure 路径核心头文件 connection.hxx、transaction_base.hxx、result.hxx、stream_from.hxx、notification.hxx构建系统定义 CMakeLists.txt、configure.ac实战参考 PostgreSQL.hpp 与 PostgreSQL.cpp连接池、通知监听、CentralDB.cppwork/result/stream_from 综合运用、README_CENTRAL_CONTROLLER.md构建依赖与控制器配置无论你是在为一个全新的 C 服务接入 PostgreSQL还是打算深入阅读或二次开发基于 libpqxx 的存储后端掌握连接字符串的优先级规则、事务生命周期work/commit、exec/exec0的语义差异以及stream_from、notification_receiver这类进阶组件都能让 libpqxx 从“一个能跑的库”变成你手中可靠的数据访问工具。【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考