使用QxOrm MONGODB进行多线程,每个线程使用不同的数据库

问题描述 投票:0回答:1

根据 QxOrm 手册:3.23.22, 好像可以用

qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("");

在每个线程中分别使用多个线程中的多个数据库。

但在实际尝试使用它时,MONGODB 实现似乎并非如此。 另外,在查看

qx::dao::call_query
的源代码时,它看起来并没有像其他 SQL 那样实现。

主要问题:我如何对 MONGODB 做同样的事情?

  1. 使用
    QXMONGODB
    驱动程序时是否定义了不同的方式来执行此操作,或者在 QxOrm 中没有以任何方式实现?
  2. 如果是后者,我如何设法解决它并实现我自己的连接池并将其与 QxOrm 一起使用?因为 MONGOCXX 驱动程序似乎确实包含打开多个数据库所需的功能。
  3. 有没有一种方法可以在 QxOrm 库和 MONGOCXX(或者可能是 MONGOC)库之间共享连接,而无需对它们的任何一个源进行重大更改?

这是 Qt 中的一个示例,我尝试查看它。

db_interactor.h

#include <QFile>
#include <QTextStream>

#include <QDebug>
#include <QJsonDocument>
#include <QObject>
#include <QxOrm.h>

class db_interactor : public QObject
{
    Q_OBJECT
public:
    explicit db_interactor(QObject *parent = nullptr);
    db_interactor(QString configFilename, QObject *parent = nullptr);

signals:

    void errorNoReturn (QString errString);
    void errorReturn (QString errString);
    void initComplete();
    void dataReady (QJsonDocument response);

public slots:
    void init();
    void runQuery();

private:
    bool inited = false;
    QHash<QString, QString> config;

    qx::QxSqlDatabase *db;
};

db_interactor.cpp

#include "db_interactor.h"

db_interactor::db_interactor(QString configFileName, QObject *parent) : QObject{parent}
{
    if (!configFileName.isEmpty())
    {
        //....
        config.insert(/*From file*/);
    }
    //...
}

void db_interactor::init()
{
    db = qx::QxSqlDatabase::getSingleton();
    qDebug () << "Database Pointer" << db;
    db->setDriverName("QXMONGODB");
    db->setHostName("localhost");
    if (config.contains("DB"))
    {
        qDebug () << "Setting DB : " << config["DB"];
        db->setDatabaseName(config["DB"]);
    }
    else
    {
        qDebug () << "_________CONFIG DOES NOT CONTAIN \"DB\"_________________";
        db->setDatabaseName("new_db");
    }
    qDebug () << "____________Initialising DB____________";
    qDebug () << db->getDatabase();
    inited = true;
    emit initComplete();
}

void db_interactor::runQuery()
{
    if (inited)
    {
        qx_query nq ("{\"insert\" : \"some_coll\" , \"documents\" : [{\"a\" : 213}]}");
        QSqlError err = qx::dao::call_query(nq);

        if (err.isValid())
        {
            qDebug () << "Error writing to db : " << err.driverText();

            emit errorReturn("Error writing to db : " + err.driverText());
        }
        else
        {
            emit errorNoReturn("Written to DB");

            qx_query bq ("cursor" , "{\"find\" : \"some_coll\"}");
            err = qx::dao::call_query(bq);
            if (err.isValid())
            {
                qDebug () << "Error reading from db : " << err.driverText();
                emit errorReturn("Error reading from db : " + err.driverText());
                return;
            }
            emit dataReady
            (QJsonDocument::fromJson(bq.response().toString().toUtf8()));
        }
        return;
    }
    errorReturn ("Not Initialised yet");
}

在另一个 QObject 类中创建该类的 2 个对象并将它们移动到单独的线程...

mainthingy.h

#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>

#include "db_interactor.h"

class mainThingy : public QObject
{
    Q_OBJECT

    QThread aFewThreads[2];
public:
    explicit mainThingy(QObject *parent = nullptr);
    // Ignore the destructor for now, as that is not the point in question
signals:
    void init1 ();
    void init2 ();

    void runQr1 ();
    void runQr2 ();

private slots:
    void dataFrom1 (QJsonDocument response);
    void dataFrom2 (QJsonDocument response);

    void showErrReturn (QString err, int thread);

private:
    db_interactor *di1, *di2;

    void f_init1();
    void f_init2();

    void f_rq1();
    void f_rq2();

    void interface();

    bool user_time = true;
    QTimer ui_timer;
};

mainthingy.cpp

#include "mainthingy.h"

#include <iostream>
#include <string>

mainThingy::mainThingy(QObject *parent)
    : QObject{parent}
{
    di1 = new db_interactor(QStringLiteral(":/conf1.ini"));
    di2 = new db_interactor(QStringLiteral(":/conf2.ini"));
    di1->moveToThread(&aFewThreads[0]);
    di2->moveToThread(&aFewThreads[1]);
    aFewThreads[0].start();
    aFewThreads[1].start();

    connect(this, &mainThingy::init1, di1, &db_interactor::init);
    connect(di1, &db_interactor::initComplete, this, [this]()
    {
        qDebug () << "DB Interactor 1 Init Complete";
        user_time = true;
    });
    connect(di2, &db_interactor::initComplete, this, [this]()
    {
        qDebug () << "DB Interactor 2 Init Complete";
        user_time = true;
    });
    connect(this, &mainThingy::init2, di2, &db_interactor::init);
    connect(this, &mainThingy::runQr1, di1, &db_interactor::runQuery);
    connect(this, &mainThingy::runQr2, di2, &db_interactor::runQuery);
    connect(di1, &db_interactor::dataReady, this, &mainThingy::dataFrom1);
    connect(di2, &db_interactor::dataReady, this, &mainThingy::dataFrom2);

    connect(di1, &db_interactor::errorReturn, this, [this] (QString eS)
    {
        showErrReturn(eS, 1);
    });
    connect(di2, &db_interactor::errorReturn, this, [this] (QString eS)
    {
        showErrReturn(eS, 2);
    });

    interface();

    connect(&ui_timer, &QTimer::timeout, this, [this] ()
    {
        if (this->user_time)
        {
            interface();
        }
    });
    ui_timer.start(2000);
}

void mainThingy::dataFrom1(QJsonDocument response)
{
    qDebug () << response;
    user_time = true;
}

void mainThingy::dataFrom2(QJsonDocument response)
{
    qDebug () << response;
    user_time = true;
}

void mainThingy::showErrReturn(QString err, int thread)
{
    std::cout << "Error in " << thread << ": " << err.toStdString() << std::endl;
    qDebug () << "Err " << 1 << err;
    user_time = true;
}

void mainThingy::f_init1()
{
    qDebug () << "void mainThingy::f_init1()";
    emit init1();
}

void mainThingy::f_init2()
{
    qDebug () << "void mainThingy::f_init2()";
    emit init2();
}

void mainThingy::f_rq1()
{
    qDebug () << "void mainThingy::f_rq1()";
    emit runQr1();
}

void mainThingy::f_rq2()
{
    qDebug () << "void mainThingy::f_rq2()";
    emit runQr2();
}

void mainThingy::interface()
{
    // Made a crude little CLI to get to the real problem
    qDebug () << "void mainThingy::interface()";
    std::cout << "Ready for command" << std::endl;
    std::string usrResp;
    std::cin >> usrResp;
    QString uR = QString::fromStdString(usrResp);
    if (uR == "i1")
    {
        f_init1();
        user_time = false;
    }
    else if (uR == "i2")
    {
        f_init2();
        user_time = false;
    }
    else if (uR == "q1")
    {
        f_rq1();
        user_time = false;
    }
    else if (uR == "q2")
    {
        f_rq2();
        user_time = false;
    }
    else if (uR == "quit")
    {
        exit (0);
    }
    else
    {
        std::cout << "?" << std::endl;
        qDebug () << "??";
    }
}

qrc:/conf1.ini
qrc:/conf2.ini
中有 2 个不同的配置,我希望 q1 和 q2 将数据发送到 2 个独立的数据库。

但是,我发现了以下几点:

  1. qx::QxSqlDatabase::getSingleton()->getDatabase()
    给出了一个错误和一个空数据库
  2. 在初始化
    di1
    时,查询工作正常并将数据插入到正确的数据库中,但是在同一程序实例中初始化
    di2
    时,我发现两个查询
    "q1"
    "q2"
    将数据插入到初始化的数据库中
    di2
    。本质上,相同的配置被覆盖。
mongodb qt qthread odm qxorm
1个回答
0
投票

在 QxOrm 中使用多个数据库对于 SQL 数据库有 2 种使用方法。

  1. 创建
    QSqlDatabase
    的对象,并在调用 setXXXX() 函数时传递指针,并在调用查询时使用该对象。
  2. 只要程序中每个线程只有一个数据库配置,在调用 setXXXX() 函数时,为
    true
    传递
    bJustForCurrentThread
    ,QxOrm 会根据文档进行处理。
void setDriverName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setDatabaseName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setHostName(const QString & s, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);
void setPort(int i, bool bJustForCurrentThread = false, QSqlDatabase * pJustForThisDatabase = NULL);

对于

QXMONGODB
驱动程序,您可以选择在不同线程中打开多个数据库,并且只要在调用 setXXXX() 函数时为
true
传递
bJustForCurrentThread
,它将按预期工作。

在上面的问题中,我没有在参数

true
中传递
bJustForCurrentThread
,这导致为所有其他线程设置任何一个应用程序线程中的配置,从而出现了我遇到的问题。

结论:

  1. QSqlDatabase
    无法与 MONGODB 驱动程序一起使用,因为
    QSqlDatabase
    适用于 SQL 数据库
  2. 我实现上述示例的方式,即使与预期的其他驱动程序一起使用,它也无法工作。
  3. call_query()
    MONGODB 的实现表面上看起来有所不同,但内部实现仍然具有对不同线程中的多个数据库所需的支持。
© www.soinside.com 2019 - 2024. All rights reserved.