linux系统下PostgreSQL的使用

文章目录


前言

最近工作中使用到了pgsql,主要是使用其c++驱动完成数据库创建及增删改查等操作...

一、安装pgsql数据库

使用命令如下:

cpp 复制代码
sudo apt-get install postgresql

安装完成,使用如下命令,确认数据库版本:

cpp 复制代码
psql --version

二、安装c和c++驱动

使用如下命令安装c驱动:

cpp 复制代码
sudo apt-get install libpq-dev

使用如下命令安装c++驱动:

cpp 复制代码
sudo tar -zxvf libpqxx-6.4.8.tar.gz
cd libpqxx-6.4.8/
sudo ./configure --disable-documentation
sudo make
sudo make install

三、使用

1、头文件

头文件如下:

cpp 复制代码
#ifndef POSTGREOPERATOR_H
#define POSTGREOPERATOR_H

#include <iostream>
#include <string>
#include <map>
#include <thread>

#include "pqxx/pqxx"

using namespace std;
using namespace pqxx;

struct TableField {
    string name;
    string type;
};

class PostgreOperator
{
private:
    PostgreOperator() {}
    PostgreOperator(const PostgreOperator&) = delete;
    PostgreOperator& operator=(const PostgreOperator&) = delete;
    ~PostgreOperator();

public:
    static PostgreOperator& getInstance();

    bool connect();
    void disConnect();

    bool insertOneRow(const string& tableName,const vector<string>& rowData);
    bool updateOneRow(const string& tableName, const string& conditionColumnName,
                   const string& conditionValue, const vector<string>& columnNames,
                   const vector<string>& newValues);
    void selectRows(const string& tableName, vector<vector<string>>& resultRows,
                    const vector<string>& selectedColumns,
                    const string& conditionColumnName = "",const string& conditionValue = "");
    bool deleteRows(const string& tableName, const string& conditionColumnName = "",
                      const string& conditionValue = "");

private:
    static void initTable();
    static bool createdb(const string& dbname,const string& user,const string& password);
    static bool createInitTable();

    static bool addTable(const string& tableName,const vector<TableField>& fields);
    static bool deleteTable(const string& tableName);

    static bool addFieldToTable(const string& tableName, const vector<TableField>& fields);
    static bool removeFieldFromTable(const string& tableName, const vector<string>& fieldNames);

private:
    static string m_user;
    static string m_passwd;
    static string m_dbName;
    static bool m_initTable;
    static PostgreOperator *m_instance;
    static map<string, vector<TableField>> m_tables;
    static connection* m_pConnection;
    static thread_local unique_ptr<connection> thread_local_connection_;
};

#endif // POSTGREOPERATOR_H

2、源文件

源文件如下:

cpp 复制代码
#include "postgreoperator.h"

string      PostgreOperator::m_dbName;
string      PostgreOperator::m_user;
string      PostgreOperator::m_passwd;
bool        PostgreOperator::m_initTable = false;
connection* PostgreOperator::m_pConnection = nullptr;

map<string, vector<TableField>> PostgreOperator::m_tables;
PostgreOperator* PostgreOperator::m_instance = nullptr;
thread_local unique_ptr<connection> PostgreOperator::thread_local_connection_ = nullptr;

PostgreOperator& PostgreOperator::getInstance()
{
    if (!m_instance) {
        m_instance = new PostgreOperator;
        if(!m_initTable){
            initTable();
            createdb("disposaldb","tami","tami");
            createInitTable();
        }
    }

    return *m_instance;
}

PostgreOperator::~PostgreOperator()
{
    if(m_pConnection){
        m_pConnection->disconnect();
        delete m_pConnection;
        m_pConnection = nullptr;
    }
}

bool PostgreOperator::createdb(const string& dbname,const string& user,const string& password)
{
    m_dbName = dbname;
    m_user = user;
    m_passwd = password;
    string connectStr = "dbname=postgres user=postgres password=postgres "
                        "hostaddr=127.0.0.1 port=5432";
    bool ret = false;

    try {
        connection *connection = new pqxx::connection(connectStr);

        if(connection->is_open()){
            nontransaction txn(*connection);
            string quotedDb = "'" + dbname + "'";

            if(user.compare("postgres") == 0 && password.compare("postgres") == 0){
                //cout<<"hello111 "<<"user ="<<user<<"password ="<<password<<endl;
                string checkDb = "SELECT 1 FROM pg_database WHERE datname = " + quotedDb;
                pqxx::result result_check = txn.exec(checkDb);
                if(result_check.empty()){
                    string sql = "CREATE DATABASE " + dbname + " WITH OWNER= postgres"+" ENCODING='UTF-8' ;";
                    txn.exec(sql);
                    cout << "create database "+ dbname +" with user=postgres successed!" << endl;
                }
                else{
                    cout << "database "+ dbname + " already exists!" <<endl;
                }
            }
            else{
                //cout<<"hello222 "<<"user ="<<user<<" password ="<<password<<endl;
                string quotedUser = "'" + user + "'";
                string checkUser = "SELECT 1 FROM pg_user WHERE usename = " + quotedUser;
                pqxx::result result_checkUser = txn.exec(checkUser);
                if (result_checkUser.empty()) {
                    string sql = "CREATE USER " + user + " WITH PASSWORD '" + password + "'";
                    txn.exec(sql);
                }
                else{
                    cout << "user "+ user + " already exists!" <<endl;
                }
                std::string checkDb = "SELECT 1 FROM pg_database WHERE datname = " + quotedDb;
                pqxx::result result_check = txn.exec(checkDb);
                if(result_check.empty()){
                    string dbSql = "CREATE DATABASE " + dbname + " WITH OWNER="+user+" ENCODING='UTF-8';";
                    txn.exec(dbSql);
                    cout << "create database "+ dbname +" with user="+user+" successed!" << endl;
                }
                else{
                    cout << "database "+ dbname + " already exists!" <<endl;
                }
            }

            ret = true;
        }else{
            cout<<"open database " + dbname +" with user=postgres failed!"<<endl;
            connection->disconnect();

            return ret;
        }
        delete connection;
        connection = nullptr;
    }catch (const std::exception &e) {
        cerr<<e.what()<<endl;
    }

    return ret;
}

void PostgreOperator::initTable()
{
    m_tables.clear();
    m_tables = {
        {"p_frequency", {
            {"msgId", "bigint"},
            {"sn", "bigint"},
            {"startFrequency", "bigint"},
            {"endFrequency", "bigint"},
            {"rbw", "double precision"},
            {"dataType", "smallint"},
            {"number", "integer"},
        }},
        {"d_frequency", {
            {"msgId", "bigint"},
            {"sn", "bigint"},
            {"times", "timestamp without time zone"},
            {"timems", "timestamp without time zone"},
            {"data", "smallint[]"},
        }},
        {"p_timedomain", {
             {"msgId", "bigint"},
             {"sn", "bigint"},
             {"centerFrequency", "bigint"},
             {"gain", "smallint"},
             {"timestamp", "timestamp without time zone"},
             {"frameTotal", "integer"},
             {"frameNumber", "integer"},
             {"number", "integer"},
        }},
        {"d_timedomain", {
             {"msgId", "bigint"},
             {"sn", "bigint"},
             {"times", "timestamp without time zone"},
             {"timems", "timestamp without time zone"},
             {"data", "integer[]"},
        }},
    };
}

bool PostgreOperator::createInitTable()
{
    string connectStr = "dbname="+m_dbName+" user="+m_user+" password="+m_passwd+
                        " hostaddr=127.0.0.1 port=5432";
    bool ret = false;

    try {
        m_pConnection = new pqxx::connection(connectStr);
        if(m_pConnection->is_open()){
            nontransaction txn(*m_pConnection);

            for (const auto& table : m_tables) {
                const std::string tableName = table.first;
                const std::vector<TableField>& fields = table.second;

                string quotedtable = "'" + tableName + "'";
                string checktable = "SELECT 1 FROM information_schema.tables WHERE table_name = " + quotedtable;
                //cout<<"checktable ="<<checktable<<endl;
                pqxx::result result_check = txn.exec(checktable);

                if (result_check.empty()) {
                    string quotedTableName = "\"" + tableName + "\"";
                    string createTableQuery = "CREATE TABLE " + quotedTableName + " (";
                    string idStr = "id";
                    string msgIdStr = "msgId";
                    string snStr = "sn";

                    createTableQuery += "\"" + idStr + "\" ";
                    createTableQuery += " BIGSERIAL, ";

                    for (size_t i = 0; i < fields.size(); i++) {
                        if (fields[i].name == msgIdStr || fields[i].name == snStr) {
                            createTableQuery += "\"" + fields[i].name + "\" " + " " + fields[i].type;
                            createTableQuery += " NOT NULL";
                        } else {
                            createTableQuery += "\"" + fields[i].name + "\" " + " " + fields[i].type;
                        }
                        if (i < fields.size() - 1) {
                            createTableQuery += ", ";
                        }
                    }

                    createTableQuery += ", PRIMARY KEY (\"" + idStr + "\")";
                    createTableQuery += ")";
                    //cout<<"createTableQuery ="<<createTableQuery<<endl;
                    txn.exec(createTableQuery);
                    cout << "create table " + tableName + " succeeded!" << endl;
                } else {
                    cout << "table " + tableName + " already exists!" << endl;
                }
            }

            ret = true;
        }


    } catch (const std::exception& e) {
        cerr << e.what() << endl;
    }

    return ret;
}

bool PostgreOperator::connect()
{
    if (!thread_local_connection_) {
        std::string connectStr = "dbname=" + m_dbName + " user=" + m_user + " password=" + m_passwd
                                + " hostaddr=127.0.0.1 port=5432";
        try {
            thread_local_connection_.reset(new pqxx::connection(connectStr));

            if (thread_local_connection_->is_open()) {
                cout << "Connected to dbname=" << m_dbName << " with user=" << m_user << " succeeded!" << endl;
                return true;
            } else {
                cout << "Failed to connect to dbname=" << m_dbName << " with user=" << m_user << endl;
                return false;
            }
        } catch (const std::exception& e) {
            std::cerr << "Connection failed: " << e.what() << std::endl;
            return false;
        }
    }

    return true;
}

void PostgreOperator::disConnect()
{
    if (thread_local_connection_) {
        thread_local_connection_->disconnect();
        thread_local_connection_.reset();
    }
}

bool PostgreOperator::addFieldToTable(const string& tableName, const vector<TableField>& fields)
{
    bool ret = false;

    try {
        work txn(*m_pConnection);
        string quotedtable = "'" + tableName + "'";
        string checktable = "SELECT 1 FROM information_schema.tables WHERE table_name = " + quotedtable;
        pqxx::result result_check = txn.exec(checktable);

        if (!result_check.empty()) {
            for(const auto& field : fields){
                string columnName = "'" + field.name + "'";
                string sql = "SELECT column_name FROM information_schema.columns WHERE table_name = '" + tableName + "' AND column_name = " +columnName;
                //cout<<"select sql ="<<sql<<endl;
                pqxx::result result = txn.exec(sql);
                if(result.empty()){
                    string sql = "ALTER TABLE "+ tableName+" ADD COLUMN ";
                    sql += "\"" + field.name + "\" " + " " + field.type;
                    //cout<<"alter add sql ="<<sql<<endl;
                    txn.exec(sql);
                    cout << "addFieldToTable successfully." << endl;
                    ret = true;
                }
                else{
                    cout<<"column "+field.name+" of "+tableName+" already exists!"<<endl;
                }
            }
        }
        else{
           cout << "table " + tableName + " does not exist!" << endl;
        }
        txn.commit();
    } catch (const std::exception& e) {
        cerr << e.what() << endl;
    }

    return ret;
}

bool PostgreOperator::removeFieldFromTable(const string& tableName, const vector<string>& fieldNames)
{
    bool ret = false;

    try {
        work txn(*m_pConnection);
        string quotedtable = "'" + tableName + "'";
        string checktable = "SELECT 1 FROM information_schema.tables WHERE table_name = " + quotedtable;
        pqxx::result result_check = txn.exec(checktable);

        if (!result_check.empty()) {
            for(const auto& field : fieldNames){
                string columnName = "'" + field + "'";
                string sql = "SELECT column_name FROM information_schema.columns WHERE table_name = '" + tableName + "' AND column_name = " +columnName;
                //cout<<"select sql ="<<sql<<endl;
                pqxx::result result = txn.exec(sql);
                if(!result.empty()){
                    string sql = "ALTER TABLE "+ tableName+" DROP COLUMN ";
                    sql += "\"" + field + "\" " + " ";
                    //cout<<"alter drop sql ="<<sql<<endl;
                    txn.exec(sql);
                    cout << "removeFieldFromTable successfully." << endl;
                    ret = true;
                }
                else{
                    cout<<"column "+field+" of "+tableName+" does not exists!"<<endl;
                }
            }
        }
        else{
           cout << "table " + tableName + " does not exist!" << endl;
        }
        txn.commit();
    } catch (const std::exception& e) {
        cerr << e.what() << endl;
    }

    return ret;
}

bool PostgreOperator::addTable(const string& tableName, const vector<TableField>& fields)
{
    bool ret = false;
    work txn(*m_pConnection);

    string quotedtable = "'" + tableName + "'";
    string checktable = "SELECT 1 FROM information_schema.tables WHERE table_name = " + quotedtable;
    //cout<<"checktable ="<<checktable<<endl;
    pqxx::result result_check = txn.exec(checktable);

    if (result_check.empty()) {
        string quotedTableName = "\"" + tableName + "\"";
        string createTableQuery = "CREATE TABLE " + quotedTableName + " (";
        string idStr = "id";
        string msgIdStr = "msgId";
        string snStr = "sn";

        createTableQuery += "\"" + idStr + "\" ";
        createTableQuery += " BIGSERIAL, ";
        createTableQuery += "\"" + msgIdStr + "\" ";
        createTableQuery += " bigint NOT NULL, ";
        createTableQuery += "\"" + snStr + "\" ";
        createTableQuery += " bigint NOT NULL, ";

        if(!fields.empty()){
            for (size_t i = 0; i < fields.size(); i++) {
                createTableQuery += "\"" + fields[i].name + "\" " + " " + fields[i].type;
                if (i < fields.size() - 1) {
                    createTableQuery += ", ";
                }
            }
            createTableQuery += ", PRIMARY KEY (\"" + idStr + "\")";
        }
        else{
            createTableQuery += " PRIMARY KEY (\"" + idStr + "\")";
        }
        createTableQuery += ")";
        txn.exec(createTableQuery);
        txn.commit();
        //cout<<"createTableQuery ="<<createTableQuery<<endl;
        cout << "create table " + tableName + " succeeded!" << endl;

        m_tables[tableName] = fields;

//        for (const auto& table : m_tables) {
//            const string tableName = table.first;
//            cout<<"tablename ="<<tableName<<endl;

//            const vector<TableField>& fields = table.second;
//            for(const auto& field : fields){
//                cout<<"name="<<field.name<<"type ="<<field.type;
//            }
//            cout<<endl;
//        }

        ret = true;
    } else {
        cout << "table " + tableName + " already exists!" << endl;
    }

    return ret;
}

bool PostgreOperator::deleteTable(const string& tableName)
{
    bool ret = false;

    try {
        string sql = "DROP TABLE IF EXISTS " + tableName;
        pqxx::work txn(*m_pConnection);
        txn.exec(sql);

        if(!m_tables.empty()){
            auto it = m_tables.find(tableName);
            if (it != m_tables.end()) {
                m_tables.erase(it);
                //cout << "Table '" << tableName << "' deleted from m_tables successfully." << endl;
                ret = true;
            } else {
                cout << "Table '" << tableName << "' not found from m_tables." << endl;
            }
        }
        txn.commit();
    } catch (const std::exception& e) {
        cerr << e.what() << endl;
    }

    return ret;
}

bool PostgreOperator::insertOneRow(const string& tableName,const vector<string>& rowData)
{
    bool ret = false;
    pqxx::work txn(*thread_local_connection_);

    try {
        std::string sql = "INSERT INTO " + tableName + " (";

        for (const auto& table : m_tables) {
            const std::string tableNameStr = table.first;
            const std::vector<TableField>& fields = table.second;

            if(tableNameStr == tableName){
                for (size_t i = 0; i < fields.size(); i++) {
                    sql += "\"" + fields[i].name + "\" ";

                    if (i != fields.size() - 1) {
                        sql += ",";
                    }
                }
            }
        }
        sql += ") VALUES (";
        for (size_t i = 0; i < rowData.size(); i++) {
            sql += "'" + rowData[i] + "'";

            if (i != rowData.size() - 1) {
                sql += ",";
            }
        }

        sql += ")";
        //cout<<"insert sql ="<<sql<<endl;

        txn.exec(sql);
        txn.commit();

        ret = true;
    } catch (const std::exception &e) {
        cerr<<e.what()<<endl;
        txn.abort();
    }

    return ret;
}

bool PostgreOperator::updateOneRow(const string& tableName, const string& conditionColumnName,
               const string& conditionValue, const vector<string>& columnNames,
               const vector<string>& newValues)
{
    bool ret = false;

    try {
        pqxx::work txn(*thread_local_connection_);

        std::string sql = "UPDATE " + tableName + " SET ";

        for (size_t i = 0; i < columnNames.size(); i++) {
            string columnName = "\"" + columnNames[i] + "\" ";
            sql += columnName + " = '" + newValues[i] + "'";

            if (i != columnNames.size() - 1) {
                sql += ",";
            }
        }

        string conditionName = "\"" + conditionColumnName + "\" ";
        sql += " WHERE " + conditionName + " = '" + conditionValue + "'";
        txn.exec(sql);
        txn.commit();

        cout << "Data updated successfully." << endl;
        ret = true;
    } catch (const std::exception &e) {
        cerr << e.what() << endl;
    }

    return ret;
}

void PostgreOperator::selectRows(const string& tableName, vector<vector<string>>& resultRows, const vector<string>& selectedColumns,
                                 const string& conditionColumnName,const string& conditionValue)
{
    try {
        pqxx::work txn(*thread_local_connection_);

        string sql;// = "SELECT * FROM " + tableName;
        if (!selectedColumns.empty()) {
            sql = "SELECT ";
            for (size_t i = 0; i < selectedColumns.size(); ++i) {
                sql += "\"" + selectedColumns[i] + "\"";
                if (i < selectedColumns.size() - 1)
                    sql += ",";
            }
            sql += " FROM " + tableName;
        } else {
            sql = "SELECT * FROM " + tableName;
        }

        if(!conditionColumnName.empty() && !conditionValue.empty()) {
            string conditionName = "\"" + conditionColumnName + "\" ";
            sql += " WHERE " + conditionName + " = '" + conditionValue + "'";
        }

        pqxx::result result = txn.exec(sql);
        for (const auto& row : result) {
            vector<string> record;
            for (const auto& field : row) {
                //cout << field.name() << ": " << field.c_str() << "     ";
                record.push_back(field.c_str());
            }
            resultRows.push_back(record);
            //cout << endl;
        }

        txn.commit();

        cout << "Data select successfully." << endl;
    } catch (const std::exception &e) {
        cerr << e.what() << endl;
    }
}

bool PostgreOperator::deleteRows(const string& tableName, const string& conditionColumnName,
                                   const string& conditionValue)
{
    bool ret = false;
    pqxx::work txn(*thread_local_connection_);

    try {
        string sql = "DELETE FROM " + tableName;
        if(!conditionColumnName.empty() && !conditionValue.empty()) {
            string conditionName = "\"" + conditionColumnName + "\" ";
            sql += " WHERE " + conditionName + " = '" + conditionValue + "'";
        }
        cout<<"deleterows sql = "<<sql<<endl;
        txn.exec(sql);
        txn.commit();

        cout << "Data delete successfully." << endl;

        ret = true;
    } catch (const std::exception &e) {
        cerr << e.what() << endl;

        txn.abort();
    }

    return ret;
}

3、main文件

cpp 复制代码
#include <chrono>
#include <iostream>
#include <thread>

#include "postgreoperator.h"

void insertfun(int id,PostgreOperator &operatorInstance) {
    if (!operatorInstance.connect()) {
        std::cerr << "Thread " << id << " failed to connect to the database." << std::endl;
        return;
    }
    string tableName = "p_frequency";

    for(int i = 0;i<500;i++){
        vector<string> data = {"12345", "10086", "0", "2000000", "0.1", "1", "10"};
        operatorInstance.insertOneRow(tableName, data);
    }

    for(int i = 500;i<1000;i++){
        vector<string> data = {"67890", "10086", "0", "2000000", "0.1", "1", "10"};
        operatorInstance.insertOneRow(tableName, data);
    }
}

void deletefun(int id,PostgreOperator &operatorInstance)
{
    if (!operatorInstance.connect()) {
        std::cerr << "Thread " << id << " failed to connect to the database." << std::endl;
        return;
    }
    string tableName = "p_frequency";
    string conditionColumnName = "msgId";
    string conditionValue = "12345";

    operatorInstance.deleteRows(tableName, conditionColumnName, conditionValue);
}

int main(int argc, char *argv[])
{
    PostgreOperator& operatorInstance = PostgreOperator::getInstance();
    // 创建并启动多个线程
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(insertfun, i,std::ref(operatorInstance));
    }

    // 等待所有线程完成
    for (auto& thread : threads) {
        thread.join();
    }

#if 0
    std::thread t1(deletefun, 5, std::ref(operatorInstance));
    t1.join();

#endif

    return 1;
}

4、编译

命令如下:

cpp 复制代码
g++ -pthread --std=c++11 -o demo.out main.cpp postgreoperator.cpp -lpqxx -lpq
相关推荐
人类群星闪耀时2 分钟前
利用AI进行系统性能优化:智能运维的新时代
运维·人工智能·性能优化
小安运维日记14 分钟前
CKA认证 | Day7 K8s存储
运维·云原生·容器·kubernetes·云计算
LinuxSuRen18 分钟前
Jenkins 命令行多线程并发下载制品包
运维·jenkins
存储服务专家StorageExpert21 分钟前
墙裂推荐:console, CLI命令行和日志使用字体-Cascadia
运维·服务器·netapp存储·存储维护·emc存储
暗碳25 分钟前
华为麦芒5(安卓6)termux记录 使用ddns-go,alist
android·linux
靡樊27 分钟前
Linux:基础IO
linux
IvorySQL1 小时前
2024 开放原子开发者大会活动回顾|瀚高 IvorySQL 开源数据库在国产软件的开源实践
数据库·postgresql·开源数据库·国产数据库·ivorysql
菜鸟康1 小时前
Linux系统编程——理解系统内核中的信号捕获
linux·运维·服务器
张明奇-琦玉1 小时前
Boost之log日志使用
linux·服务器·算法
云计算DevOps-韩老师1 小时前
【网络云计算】2024第52周-每日【2024/12/26】小测-理论&实操-备份MySQL数据库并发送邮件-解析
linux·开发语言·网络·数据库·mysql·云计算·perl