Libpqxx连接池

4
我正在尝试使用libpqxx库开发一个非常简单和直接的连接池。我对c++还很陌生,指针和引用仍然让我感到困惑。该类的行为非常简单:有一个带有一些已初始化连接的向量,并在需要时弹出和推送连接到向量中。由于指针和引用的错误实现,代码存在许多错误。请给我一些提示。
编辑:我成功修复了所有编译错误。当我运行main函数时,它会给我一个分段错误。
class DbPool {

公共:

pqxx::result runQuery(const string& query) {

    connection *conn = getCon();
    work trans(*conn);
    result res = trans.exec(query);
    trans.commit();
    releaseCon(conn);

    return res;
}

DbPool(uint32_t max_cons) {

    for (uint32_t i = 0; i < max_cons; i++) {

        connection* con = createCon();
        m_freeCons.push_back(shared_ptr < connection > (con));
    }
}

私有:

connection * createCon() {

    connection * conn =
            new connection(
                    "user='ak' password='rootpassword' dbname='bips_office' hostaddr='127.0.0.1' port='5432'");
    return conn;
}

void releaseCon(connection *con) {

    m_freeCons.push_back(shared_ptr < connection > (con));
}

connection* getCon() {

    shared_ptr < connection > conn = *(m_freeCons.end() - 1);
    m_freeCons.pop_back();
    return conn.get();
}

vector<shared_ptr<connection> > m_freeCons;

};

int main(int argc, char *argv[]) {
     DbPool *pool = new DbPool(5);
     result res = pool->runQuery("SELECT COUNT (*) from captures");
     return 0;
}

1
代码有很多错误 - 你是指编译错误,还是运行时错误对程序运行产生了一些影响,或者你指的是设计缺陷?请澄清。 - codeling
由于我对指针的经验不足,设计缺陷导致编译错误。 - JoaoFLF
请在这里展示它们!这会让我们的生活更加轻松。 - codeling
2个回答

2
如果您担心设计问题,以下是我的建议:
  • 您的代码是否可以编译?我认为不行,因为您正在使用指向连接的指针向后添加连接对象(“m_freeCons.push_back(*con);” - “*”解除了指向连接的指针)...
  • 通常不建议将可修改的成员句柄提供给外部(就像您在“getCon”方法中所做的那样 - 至少返回一个“connection const *”,如果可能的话)
  • 如果必须使用指针集合,请考虑使用共享指针而不是原始指针 - 这样您就不必担心释放内存;或者使用Boost.PointerContainer;还可以参见这里
  • 关于奇怪的风格问题:为什么要使用“return &(*conn)”?这会对指针“conn”进行解引用,然后再次获取其地址。相反,您可以简单地写成“return conn”!

回答您使用shared_ptr重新编写的问题: 您仍然需要使用new创建连接,并将shared_ptr包装在其中;例如,对于createCon:

connection * createCon(){

    connection * conn = new connection("user='ak' password='rootpassword' dbname='bips_office' hostaddr='127.0.0.1' port='5432'");
    return conn;
}

并且

    connection* con = createCon();
    m_freeCons.push_back(shared_ptr<connection>(con));

并且在其他地方类似地进行。


你知道一些创建 shared_ptr 向量并执行操作(例如获取最后一个对象、填充向量以及执行 push 和 pop)的示例吗? - JoaoFLF
我为你看到的其中一条错误信息添加了一些更正,其他信息应该是类似的,但请参考 shared_ptr 的教程,而不是顺序更新你的问题。这个网站是为解决具体问题而存在的,而不是用于修复变化和无法编译的代码。 - codeling
我查看了一些教程并成功解决了所有编译错误。你能检查一下我上面的编辑吗? - JoaoFLF
如果编译和运行都没有问题,还需要检查什么呢?只需“查看一下”即可,这是在 http://codereview.stackexchange.com/ 上进行的。 - codeling

1
受您的帖子启发,我在自己的项目中使用了这个简单的连接池。我使用了std::stack.进行推入和弹出操作。除添加连接时的try-catch外,没有进行错误检查。适用于postgresql数据库。

Database.hpp:

#include <stack>
#include <pqxx/pqxx>

class Database {
private:
    const std::string connectionString = "dbname=db user=usr hostaddr=127.0.0.1 port=5432";
    std::stack<pqxx::connection *> dbpool;

public:
    Database(const unsigned int);

Database.cpp:

#include "Database.hpp"

Database::Database(const unsigned int connections) {
    for (int i = 0; i < connections; ++i) {
        try {
            auto* dbconn = new pqxx::connection(connectionString);
            dbpool.emplace(dbconn);
        } catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
    }
}

main.cpp:

#include "Database.hpp"

int main(int argc, char* argv[]) {
    Database database {10};

    auto *D = dbpool.top();
    dbpool.pop();

    const std::string query = "select * from mytable";
    pqxx::nontransaction N(*D);
    pqxx::result R(N.exec(query));

    for (pqxx::result::const_iterator c = R.begin(); c != R.end(); ++c) {
        std::cout << c[1].as<std::string>() << std::endl;
    };

    dbpool.push(D);
}

使用pqxx::lazyconnection比使用pqxx::connection更好。为什么你在主函数中弹出了? - Krcn U
我立即使用pqxx::connection来建立连接。然后从堆栈中获取连接时,延迟是最小的。top()函数将给您返回堆栈中顶部项目的引用,并且pop()函数将其移除。如果不移除它,其他连接可能会获取相同的连接。尽管这段代码不是线程安全的,但是在后续版本中我已经使用互斥锁来实现了线程安全性。 - kometen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接