PostgreSQL C++客户端API libpqxx的使用

news/2024/10/30 23:01:19/

      PostgreSQL是一个先进的、开源的、免费的、功能强大的关系型数据库,缩写版是postgres。它使用一种客户端/服务器(C/S)的模型。一次PostgreSQL会话由下列相关的进程(程序)组成:

      (1).一个服务器进程,它管理数据库文件、接受来自客户端应用与数据库的连接并且代表客户端在数据库上执行操作。该数据库服务器程序叫做postgres。

      (2).那些需要执行数据库操作的用户的客户端(前端)应用。客户端应用可能本身就是多种多样的:可以是一个面向文本的工具,也可以是一个图形界面的应用,或者是一个通过访问数据库来显示网页的网页服务器,或者是一个特制的数据库管理工具。

      和典型的客户端/服务器应用一样,这些客户端和服务器可以在不同的主机上。这时它们通过TCP/IP网络连接通讯

      PostgreSQL服务器可以处理来自客户端的多个并发请求。因此,它为每个连接启动("forks")一个新的进程。从这个时候开始,客户端和新服务器进程就不再经过最初的postgres进程的干涉进行通讯。因此,守护者服务器进程总是在运行并等待着客户端连接,而客户端和相关联的服务器进程则是起起停停。

      一台运行着的PostgreSQL服务器可以管理许多数据库。通常我们会为每个项目和每个用户单独使用一个数据库。

      libpqxxPostgreSQL的官方C++客户端API,源码地址:https://github.com/jtv/libpqxx,最新发布版本为7.9.2,license为BSD-3-Clause。

      Windows10上使用CMake编译libpqxx:

      1.build.sh脚本内容如下:

#! /bin/bashif [ $# != 2 ]; thenecho "Error: requires two parameters: 1: dynamic or static; 2: Relese or Debug"echo "For example: dynamic library, debug mode: $0  dynamic Debug"exit -1
fiif [ $1 != "dynamic" ] && [ $1 != "static" ]; thenecho "Error: the first parameter can only be dynamic or static"exit -1
fiif [ $2 != "Release"  ] && [ $2 != "Debug" ]; thenecho "Error: the second parameter can only be Release or Debug"exit -1
fiif [[ ! -d "build" ]]; thenmkdir buildcd build
elsecd build
fidynamic_flag=ON
if [ $1 != "dynamic" ]; thendynamic_flag=OFF
fiecho "build: $1 $2"# vs2022, PostgreSQL 16.4cmake \-G"Visual Studio 17 2022" -A x64 \-DPostgreSQL_ROOT="D:/ProgramFiles/PostgreSQL/16" \-DCMAKE_BUILD_TYPE=$2 \-DCMAKE_CONFIGURATION_TYPES=$2 \-DBUILD_SHARED_LIBS=${dynamic_flag} \-DCMAKE_INSTALL_PREFIX=./install \..
make -j2
cmake --build . --target install --config $2

      2.注意:

      (1).编译libpqxx需要安装PostgreSQL,参考:https://blog.csdn.net/fengbingchun/article/details/141750748,或者至少需要安装用于客户端开发的C头文件和库。库libpqxx建立在PostgreSQL的标准C API libpq之上。

      (2).7.x版本至少需要C++17,对于8.x至少需要C++20。

      (3).推荐:windows上使用动态库,其它平台使用静态库。

      以下为测试代码段:

      (1).创建数据库:

int create_database(const std::string& dbname)
{try {pqxx::connection c{ options + "postgres" }; // database postgres must already existc.set_client_encoding("GBK");pqxx::nontransaction tx{ c };const std::string str{ "CREATE DATABASE " };tx.exec(str + dbname);}catch (const std::exception& e) {std::cerr << "Error:create database: " << e.what() << std::endl;outfile << "Error:create database: " << e.what() << std::endl;return -1;}return 0;
}

      (2).连接数据库:

int connect_database(const std::string& dbname)
{try {pqxx::connection c{ options + dbname };//c.set_client_encoding("GBK"); // GBK, default:UTF8if (c.is_open())std::cout << c.dbname() << " database was opened successfully" << std::endl;else {std::cerr << "Error:failed to open database:" << dbname << std::endl;return -1;}std::cout << "dbname:" << c.dbname() << ", username:" << c.username()<< ", hostname:" << c.hostname() << ", port:" << c.port()<< ", backendpid:" << c.backendpid() << ", sock:" << c.sock()<< ", protocol_version:" << c.protocol_version()<< ", server_version:" << c.server_version()<< ", get_client_encoding:" << c.get_client_encoding()<< ", encoding_id:" << c.encoding_id()<< ", get_notifs:" << c.get_notifs()<< std::endl;}catch (const std::exception& e) {std::cerr << "Error:connect database: " << e.what() << std::endl;outfile << "Error:connect database: " << e.what() << std::endl;return -1;}return 0;
}

      (3).删除数据库:

int drop_database(const std::string& dbname)
{try {pqxx::connection c{ options + "postgres" };c.set_client_encoding("GBK");pqxx::nontransaction tx{ c };const std::string str{ "DROP DATABASE " };tx.exec(str + dbname);}catch (const std::exception& e) {std::cerr << "Error:drop database: " << e.what() << std::endl;outfile << "Error:drop database: " << e.what() << std::endl;return -1;}return 0;
}

      (4).创建表:

int create_table(const std::string& dbname, const std::string& command)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);w.exec(command);w.commit();}catch (const std::exception& e) {std::cerr << "Error:create table: " << e.what() << std::endl;outfile << "Error:create table: " << e.what() << std::endl;return -1;}return 0;
}

      (5).删除表:

int drop_table(const std::string& dbname, const std::string& tablename)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);const std::string str{ "DROP TABLE " };w.exec(str + tablename);w.commit();}catch (const std::exception& e) {std::cerr << "Error:drop table: " << e.what() << std::endl;outfile << "Error:drop table: " << e.what() << std::endl;return -1;}return 0;
}

      (6).向表中插入数据:

int insert_into_teacher(const std::string& dbname, int id, const std::string& name, const std::string& addr, const std::string& sex)
{try {pqxx::connection c{ options + dbname + " options='-c client_encoding=GBK'" }; // 有中文时需设置client_encoding=GBK,否则数据库中会显示乱码,推荐使用:c.set_client_encoding("GBK")pqxx::work w(c);const std::string query{ "INSERT INTO teacher (id, name, addr, sex) VALUES ($1, $2, $3, $4)" };w.exec_params(query, id, name, addr, sex);w.commit();}catch (const std::exception& e) {std::cerr << "Error:insert into: " << e.what() << std::endl;outfile << "Error:insert into: " << e.what() << std::endl;return -1;}return 0;
}std::string get_current_time()
{auto timenow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());std::tm* now_tm = std::localtime(&timenow);std::ostringstream oss;oss << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S");return oss.str();
}int insert_into_student(const std::string& dbname, int id, const std::string& name, const std::string& addr, int age,float score, const std::string& date, const std::string& sex)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK"); // 有中文时需设置client_encoding=GBK,否则数据库中会显示乱码pqxx::work w(c);const std::string query{ "INSERT INTO student (id, name, addr, age, score, date, sex) VALUES ($1, $2, $3, $4, $5, $6, $7)" };w.exec_params(query, id, name, addr, age, score, date, sex);w.commit();}catch (const std::exception& e) {std::cerr << "Error:insert into: " << e.what() << std::endl;outfile << "Error:insert into: " << e.what() << std::endl;return -1;}return 0;
}

      (7).向已有表中添加、删除列:

int alter_table(const std::string& dbname)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);const std::string query{ "ALTER TABLE teacher " };w.exec(query + "ADD COLUMN hobbies CHAR(64) DEFAULT '游泳'");w.exec(query + "DROP COLUMN addr");w.commit();}catch (const std::exception& e) {std::cerr << "Error:alter table: " << e.what() << std::endl;outfile << "Error:alter table: " << e.what() << std::endl;return -1;}return 0;
}

      (8).删除表中数据:

int delete_table_data(const std::string& dbname)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);const std::string query{ "DELETE FROM teacher WHERE id > 10000 OR sex='女'" };w.exec(query);w.commit();}catch (const std::exception& e) {std::cerr << "Error:delete: " << e.what() << std::endl;outfile << "Error:delete: " << e.what() << std::endl;return -1;}return 0;
}

      (9).调整表中已有数据:

int update_table_data(const std::string& dbname)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);const std::string query{ "UPDATE teacher SET " };w.exec(query + "sex='男' WHERE sex='man'");w.exec(query + "sex='女' WHERE sex='woman'");w.commit();}catch (const std::exception& e) {std::cerr << "Error:update: " << e.what() << std::endl;outfile << "Error:update: " << e.what() << std::endl;return -1;}return 0;
}

      (10).查询表中数据:

int select_table_data(const std::string& dbname)
{try {pqxx::connection c{ options + dbname };c.set_client_encoding("GBK");pqxx::work w(c);const std::string query{ "SELECT * FROM student WHERE age >= 20 AND date > '2024-10-25 16:43:06'" };pqxx::result r(w.exec(query));w.commit();std::cout << "empty:" << r.empty() << ", size:" << r.size() << ", columns:" << r.columns() << std::endl;std::cout << "column name: ";for (auto i = 0; i < r.columns(); ++i)std::cout << r.column_name(i) << "," << r.column_type(r.column_name(i)) << ";";std::cout << std::endl;for (const auto& row : r) {for (const auto& field : row) {std::cout << field.c_str() << "\t";}std::cout << std::endl;}}catch (const std::exception& e) {std::cerr << "Error:select: " << e.what() << std::endl;outfile << "Error:select: " << e.what() << std::endl;return -1;}return 0;
}

      全局变量设置如下:

const std::string options{ "hostaddr=127.0.0.1 port=5432 user=postgres password=spring dbname=" };
const std::string table_teacher{ "CREATE TABLE teacher (""id INTEGER PRIMARY KEY NOT NULL CHECK(id>1000),""name CHAR(32) NOT NULL,""addr CHAR(64) DEFAULT 'BeiJing',""sex CHAR(8) NOT NULL)" };
const std::string table_student{ "CREATE TABLE student (""id INTEGER PRIMARY KEY NOT NULL,""name CHAR(32) NOT NULL,""addr CHAR(64) DEFAULT 'TianJin',""age INTEGER,""score REAL,""date TIMESTAMP,""sex CHAR(8) NOT NULL)" };
std::ofstream outfile;

      主函数如下:

int test_libpqxx()
{
#ifdef _MSC_VERoutfile.open("../../../testdata/output.txt", std::ios::app);
#elseoutfile.open(../../testdata/output.txt", std::ios::app);
#endifif (!outfile.is_open()) {std::cerr << "Error:fail to open file to write\n";return -1;}// databasecreate_database("Info"); // 创建数据库时,数据库中显示的名字为info,而不是Infoconnect_database("info"); // 连接数据库时指定的数据名区分大小写//drop_database("info");// tablecreate_table("info", table_teacher);create_table("info", table_student);insert_into_teacher("info", 1111, "Tom", "HeBei", "man");insert_into_teacher("info", 5555, "Tom", "北京", "男");insert_into_teacher("info", 2222, "小张", "天津", "woman");insert_into_teacher("info", 16625, "xx", "xx", "女");insert_into_student("info", 8, "小王", "HeBei", 32, 88.8, get_current_time(), "男");std::this_thread::sleep_for(std::chrono::seconds(2));insert_into_student("info", 28, "小何", "深圳", 8, 22.22, get_current_time(), "女");insert_into_student("info", 29, "Lucy", "北京", 18, 22.22, get_current_time(), "woman");insert_into_student("info", 33, "Tom", "深圳", 28, 22.22, get_current_time(), "woman");insert_into_student("info", 18, "小李", "上海", 28, 66.6, get_current_time(), "女");std::this_thread::sleep_for(std::chrono::seconds(2));insert_into_student("info", 48, "Tom", "深圳", 38, 22.22, get_current_time(), "woman");alter_table("info");delete_table_data("info");update_table_data("info");select_table_data("info");drop_table("info", "teacher");outfile.close();std::cout << "test finish\n";return 0;
}

     

      (1).创建数据库时,数据库中显示的名字为小写;连接数据库时指定的数据名区分大小写。

      (2).有中文时需设置client_encoding为GBK。

      (3).Debug模式下,使用的也是PostgreSQL中的release库。

      数据库中student表内容如下:

      执行结果如下:

      GitHub:https://github.com/fengbingchun/Messy_Test


http://www.ppmy.cn/news/1543209.html

相关文章

【计网】从零开始认识IP协议 --- 理解网段划分,NAT策略,私有IP和公网IP,认识公网

任何收获都不是偶然&#xff0c; 一点一滴的进步终会让未来的你焕然一新&#xff01; 从零开始认识IP协议 1 为什么要进行网段划分2 特殊IP地址与数量限制3 私有IP和公网IP4 彻底理解网段划分5 认识公网 1 为什么要进行网段划分 我们以一个例子来讲解为什么要进行网段划分&a…

场景时代下“定制开发、2 + 1 链动模式、AI 智能名片、S2B2C 商城小程序”的发展与营销策略转变

摘要&#xff1a;本文深入剖析了场景的起源和特点&#xff0c;详细回顾了数据运营体系从信息技术时代到大数据时代再到场景时代的发展历程。在此基础上&#xff0c;全面探讨了定制开发、2 1 链动模式、AI 智能名片、S2B2C 商城小程序在场景时代的应用和发展&#xff0c;深度分…

【云原生】云原生后端详解:架构与实践

目录 引言一、云原生后端的核心概念1.1 微服务架构1.2 容器化1.3 可编排性1.4 弹性和可伸缩性 二、云原生后端的架构示意图三、云原生后端的最佳实践3.1 使用服务网格3.2 监控与日志管理3.3 CI/CD 流水线3.4 安全性 总结参考资料 引言 随着云计算的迅猛发展&#xff0c;云原生…

深度强化学习-学习笔记

1.PPO &#xff08;1&#xff09;DeepMind公司发明的算法PPO &#xff08;2&#xff09;OpenAI公司发明的算法PPO2&#xff1b; 近端策略优化算法&#xff08;proximal policy optimization&#xff0c;PPO&#xff09; Actor 网络输出在给定状态 S下采取每个动作的概率分布&a…

el-datepicker此刻按钮点击失效

文章目录 此刻按钮失效原因&#xff1a;使用了禁用未来日期解决办法&#xff1a;重写此刻按钮点击事件代码&#xff08;包含禁用未来日期和时分秒的处理&#xff09;框出主要代码&#xff08;因为包含禁用日期功能&#xff09;&#xff08;取你所需&#xff09; 此刻按钮失效原…

测试华为GaussDB(DWS)数仓,并通过APISQL快速将(表、视图、存储过程)发布为API

华为数据仓库服务 数据仓库服务&#xff08;Data Warehouse Service&#xff0c;简称DWS&#xff09;是一种基于公有云基础架构和平台的在线数据处理数据库&#xff0c;提供即开即用、可扩展且完全托管的分析型数据库服务。DWS是基于华为融合数据仓库GaussDB产品的云原生服务&a…

闲一品交易平台:SpringBoot技术的力量

第3章 系统分析 3.1 需求分析 闲一品交易平台主要是为了提高工作人员的工作效率和更方便快捷的满足用户&#xff0c;更好存储所有数据信息及快速方便的检索功能&#xff0c;对系统的各个模块是通过许多今天的发达系统做出合理的分析来确定考虑用户的可操作性&#xff0c;遵循开…

MySQL覆盖索引

覆盖索引&#xff08;Covering Index&#xff09;是数据库优化中的一种重要技术 覆盖索引是指一个查询语句在执行时&#xff0c;所需的数据可以完全通过索引来获取&#xff0c;而无需访问实际的数据行。也就是说&#xff0c;查询语句所需的列都包含在了创建的索引中&#xff0c…