拓冰建站拓冰建站
首页 / 资讯中心 / 正文

libpqxx 7.7.3 入门实战:用 connection、transaction、result 三大类型开发 PostgreSQL C++ 客户端

libpqxx 7.7.3 入门实战用 connection、transaction、result 三大类型开发 PostgreSQL C 客户端【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOnelibpqxx 是 PostgreSQL 官方 C 客户端 libpq 之上的一层 C 封装库本指南以其 7.7.3 版本的官方入门文档getting-started.md为核心讲透连接数据库、执行 SQL、读取结果与安全拼接参数的最小完整流程。读完本文你将掌握pqxx::connection/pqxx::work/pqxx::result三类型的协作方式能够独立写出带事务提交、异常处理与安全引号转义的可运行程序并理解它们在本仓库 ZeroTier 网络控制器nonfree/controller中如何被真实使用。一、三个最基本的类型connection、transaction、result官方入门文档开宗明义libpqxx 中最基础的三个类型是connection连接、transaction事务和result结果。它们的关系可以用一句话概括连接提供会话事务承载 SQL结果回传数据。三者按如下方式协作创建pqxx::connection对象连接到数据库详见 connection.hxx 中的connections文档组。在该连接上创建事务对象通常使用pqxx::work变体transaction的便捷别名。事务结束前调用其commit函数使工作生效如果不调用commit事务对象被销毁时工作将被回滚。在事务上调用exec、query_value、stream等函数执行 SQL语句以普通字符串传入数据流式处理详见streams文档组与 stream_from.hxx。多数exec函数返回pqxx::result对象它是行的标准容器pqxx::row每一行又是字段的容器pqxx::field访问细节见accessing-results文档组与 result.hxx。每个字段的数据在内部以 PostgreSQL 定义的文本字符串格式存储可通过字段或行的as()/to()成员函数转换为原生 C 类型。事务关闭后连接即可自由执行下一个事务——这构成了 libpqxx 使用的基本循环。值得强调的是第 2 点的提交或回滚语义commit一旦调用本次事务内的全部修改固化到数据库若中途抛出异常导致离开代码块事务对象在析构时隐式中止不会产生半提交状态。二、第一个完整示例查询 SELECT 1 并打印官方入门文档给出的第一个示例连接到默认数据库、查询简单结果、转换为int并打印同时包含基本错误处理。这是 libpqxx 程序的最小骨架值得逐行精读#include iostream #include pqxx/pqxx int main() { try { // Connect to the database. In practice we may have to pass some // arguments to say where the database server is, and so on. // The constructor parses options exactly like libpqs // PQconnectdb/PQconnect. pqxx::connection c; // Start a transaction. In libpqxx, you always work in one. pqxx::work w(c); // work::exec1() executes a query returning a single row of data. // Well just ask the database to return the number 1 to us. pqxx::row r w.exec1(SELECT 1); // Commit your transaction. If an exception occurred before this // point, execution will have left the block, and the transaction will // have been destroyed along the way. In that case, the failed // transaction would implicitly abort instead of getting to this point. w.commit(); // Look at the first and only field in the row, parse it as an integer, // and print it. // // r[0] returns the first field, which has an as...() member // function template to convert its contents from their string format // to a type of your choice. std::cout r[0].asint() std::endl; } catch (std::exception const e) { std::cerr e.what() std::endl; return 1; } }这段程序打印数字1其中蕴含了多个可复用的要点pqxx::connection c;无参构造连接构造函数的参数解析与 libpq 的PQconnectdb/PQconnect完全一致见 connection.hxx 中构造函数重载connection()、connection(char const options[])、connection(zview options)。无参时默认连接本机 5432 端口上的默认数据库连接串与相关环境变量的权威定义请查阅 PostgreSQL 官方 libpq 文档。w.exec1(SELECT 1)exec1执行查询并断言返回单行result::size_type语义见下返回pqxx::row。r[0].asint()r[0]取第一行第一列字段asint()把字段内部的文本按目标类型解析。异常兜底整个流程包裹在try/catch(std::exception const )中任何 libpqxx 异常如连接失败、SQL 错误都会落入统一处理分支。从源码看exec1实际由exec_n(1, query)实现而exec0、exec_n、query_value、stream等变体均定义于 transaction_base.hxxexec见 L273exec0见 L302-315exec1见 L325-339exec_n见 L356query_value见 L369-386stream见 L442-447它们覆盖了取全部结果 / 取零行 / 取一行 / 取 N 行 / 取单值 / 流式逐行的完整需求。result 的生命周期事务关闭后仍可使用文档特别指出事务甚至连接关闭之后result对象依然可以保留使用。绝大多数情况下这样做没有问题——你完全可以发起即忘fire and forget连接而继续处理数据。唯一的例外是如果你安装了自定义的错误消息回调error handler来接收数据库错误就必须保证连接对象存活。这个特性让结果对象与连接解耦非常适合把查询结果传递到其他处理函数或线程的场景。三、整行批量转换row::asT...()除了逐字段调用asint()还可以把一整行一次性转换为多个 C 侧类型官方文档给出了简洁示例pqxx::connection c; pqxx::work w(c); pqxx::row r w.exec1(SELECT 1, 2, Hello); auto [one, two, hello] r.asint, int, std::string(); std::cout (one two) std::strlen(hello) std::endl;这里r.asint, int, std::string()把第一列解析为int、第二列解析为int、第三列解析为std::string配合 C17 的结构化绑定structured bindings直接解包为三个变量one、two、hello输出3 5。这种写法在读取固定结构如一行配置、一条成员记录时能显著减少样板代码与字段以文本存储、按需转换的设计一脉相承。四、安全地嵌入用户输入quote转义与c_str读取把外部输入拼进 SQL 时直接字符串拼接会引入 SQL 注入风险。官方文档的第二个示例演示了正确姿势——用事务的quote函数对字符串值做转义并加引号再安全嵌入 SQL#include iostream #include stdexcept #include pqxx/pqxx int main(int argc, char *argv[]) { try { if (!argv[1]) throw std::runtime_error(Give me a string!); pqxx::connection c; pqxx::work w(c); // work::exec() returns a full result set, which can consist of any // number of rows. pqxx::result r w.exec(SELECT w.quote(argv[1])); // End our transaction here. We can still use the result afterwards. w.commit(); // Print the first field of the first row. Read it as a C string, // just like std::string::c_str() does. std::cout r[0][0].c_str() std::endl; } catch (std::exception const e) { std::cerr e.what() std::endl; return 1; } }本示例展示的新要点w.quote(argv[1])把命令行传入的字符串转义成带单引号的 SQL 字面量杜绝注入执行SELECT 用户输入得到一行一列的结果。w.exec(...)与exec1不同exec返回完整结果集pqxx::result行数任意包括零行。r[0][0].c_str()result支持result[row][col]两级下标先取行再取字段c_str()把字段文本以 C 风格字符串const char *形式读出语义与std::string::c_str()一致。关于字符串转换的更深入内容自定义类型如何接入pqxx::to_string/pqxx::from_string参见 strconv.hxx其中string_traits模板特化L148 起、nullnesstraitL92 起与to_stringL333、from_stringL293-295共同构成了字段文本 ↔ 原生类型双向转换的底层机制结果集的行/字段遍历见accessing-results文档组。五、异常处理的进阶方向入门文档提示如果需要对 libpqxx 抛出的异常做更细致的区分——例如打印失败查询的 SQL 内容——可以阅读exception文档组。在 except.hxx 中可以看到异常的层级设计pqxx::broken_connection连接中断connection.hxx 注释中明确提到连接断开时通常会得到此异常且在 Unix 上连接失败时可能收到SIGPIPE信号、pqxx::sql_error携带失败的 SQL 语句等均派生自std::runtime_error因此用catch (std::exception const )即可统一兜底而需要精细化处理时再分别捕获具体类型。六、仓库实证ZeroTier 控制器中的 libpqxx 应用本仓库将 libpqxx 作为 ZeroTier 网络控制器nonfree/controller的 PostgreSQL 客户端基础多处源码可与本文概念一一对应是最好的实战参考包含方式PostgreSQL.hpp 第 19 行#include pqxx/pqxx直接引用聚合头文件。连接对象第 41 行std::shared_ptrpqxx::connection c;持有连接第 55 行c-c std::make_sharedpqxx::connection(m_connString);用连接字符串构造连接——与入门示例的无参构造形成对照说明生产环境通常需要显式指定服务器地址、库名、用户名等参数。通知机制第 63-66 行MemberNotificationReceiver等类继承pqxx::notification_receiver在连接上注册频道channelPostgreSQL.cpp 第 96 行_conn-c-await_notification(_notification_timeout, 0);阻塞等待数据库异步通知并在onNotification中解析 JSON payload 更新成员/网络配置——这是入门文档之外的高级特性异步通知但依赖的仍是同一个pqxx::connection会话模型。断线处理PostgreSQL.hpp 第 33-35 行注释明确指出 pqxx 7 has no reconnect因此代码通过连接池检查alive()并丢弃失效连接、重新借入新连接来应对服务器重启与网络中断——印证了 7.x 版本连接不可复活、需重建的语义README.md 的升级说明中也有一旦关闭便无法重新激活连接的破坏性变更记录。由此可见入门文档的三大类型不仅是教学概念也是本仓库控制器数据库层ConnectionPoolPostgresConnection、PostgresMemberListener等的真实骨架。七、构建与链接从源码到可执行程序本仓库在 ext/libpqxx-7.7.3 内置了 libpqxx 7.7.3 的完整源码与已安装产物含install/ubuntu22.04/amd64的库与文档。根据 README.md环境要求编译需要已安装 PostgreSQL 的 C 头文件与客户端库libpq7.x 版本要求至少 C178.x 起要求 C20请确保编译器版本达标。两种构建方式CMake跨平台见 BUILDING-cmake.md或 Unix 系系统的configure脚本见 BUILDING-configure.mdGNU/Linux、macOS、BSD、AIX 等均支持。头文件引入约定程序应包含不带后缀的pqxx/connection、pqxx/pqxx等而非*.hxx这些无后缀头会自动引入真正的实现头文件如 connection.hxx既符合标准 C 包含风格编辑器又能识别出 C 代码。链接选项链接时需要同时链接 C 层libpq与 C 层libpqxx典型选项为-lpqxx -lpq。若系统存在多个版本的 libpqxx 导致链接错误可改用库二进制文件的完整路径如libpqxx.a确保使用精确版本。八、连接字符串如何指定服务器与账号libpqxx 程序通过 libpq 格式的连接字符串指定目标数据库。入门文档与 README.md 共同给出了最小必要知识连接字符串由空格分隔的attributevalue对组成例如userjohn password1x2y3z4。常用属性包括属性含义与默认值host服务器主机名以/开头则为本地 Unix 域套接字路径默认/tmp等价且覆盖环境变量PGHOSThostaddr服务器 IP 地址与host互斥port服务器端口或 Unix 连接的套接字文件名后缀等价且覆盖PGPORTdbname数据库名默认与当前用户名同名等价且覆盖PGDATABASEuser连接用户名默认当前系统用户名PostgreSQL 用户与系统用户并非同一概念requiressl设为1时强制要求加密 SSL 连接无法建立 SSL 则失败这些属性也可以由对应环境变量PGHOST、PGPORT、PGDATABASE等提供优先级为连接字符串 环境变量 内置默认值按属性逐项覆盖因此只需为非默认值的那几项显式指定即可。完整的属性清单与权威定义请查阅 PostgreSQL 官方 libpq 文档。九、小结围绕 getting-started.md 的脉络本文完整覆盖了 libpqxx 入门的三条主线连接connection→ 事务transaction/work→ 结果result/row/field的对象模型与生命周期exec/exec1/query_value/stream的语句执行家族源码见 transaction_base.hxx以及asT()、quote、c_str等数据转换与安全编码手段机制见 strconv.hxx。配合 README.md 的构建说明与本仓库 nonfree/controller/PostgreSQL.hpp 的实际用法读者应能独立编译运行入门示例并将同样的模式推广到更复杂的数据库业务中。【免费下载链接】ZeroTierOneA Smart Ethernet Switch for Earth项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门