天天看点

Qt异步访问数据库框架(不涉及数据库代码)

源码地址:https://download.csdn.net/download/wangyi463295828/86502612

框架采用生产/消费者模式+回调通知的形式,模拟数据库访问操作。在实际的生产项目中,我们访问的数据有可能来自本模块、其他插件模块、本地文件、本地数据库或者也有可能是远程数据库,这当中影响I/O访问效率的因素很多,对于网络访问,很大程度上是会受网络波动、server性能等因素的影响,在访问端,为了不影响自身业务的执行,我们可以采用异步访问的方式。等获取到数据后,再通过回调将数据抛出。

1、定义范围跟协议

包括:数据库操作类型:insert、update、delete、select;

          要执行的sql语句;

          执行完成后的回调函数

每一次查询都需要构建这样的消息协议。

//fetchdbdatamessage.h
#ifndef FETCHDBDATAMESSAGE_H
#define FETCHDBDATAMESSAGE_H

#include <QObject>
#include <QList>
#include <QStringList>

typedef std::function<void(QList<QStringList>)> DBCALLBACK;

class FetchDBDataMessage : public QObject
{
    Q_OBJECT
public:
    enum Fetch_Type {
        opt_insert = 0,
        opt_delete,
        opt_update,
        opt_select
    };

    explicit FetchDBDataMessage(QObject *parent = nullptr);
    Fetch_Type type{opt_select};
    QString strSQL;
    DBCALLBACK _func;        //注意:注册的回调函数只用来接收sql执行结果和获取数据。不能做耗时的业务操作,更不能阻塞
};

#endif // FETCHDBDATAMESSAGE_H
           
#include "fetchdbdatamessage.h"

FetchDBDataMessage::FetchDBDataMessage(QObject *parent)
    : QObject{parent}
{

}
           

2、定义业务线程

这个类主要用来在子线程中搭建生产消费者模型 ,处理业务层的数据访问请求。

//fetchdbdata.h
#ifndef FETCHDBDATA_H
#define FETCHDBDATA_H

#include <QObject>
#include <QThread>
#include "fetchdbdatamessage.h"

namespace libra {
namespace adapter{
namespace internal {
class FetchDBDataPrivate;
}

class FetchDBData : public QThread
{
    Q_OBJECT
public:
    explicit FetchDBData(QObject *parent = nullptr);
    ~FetchDBData();

    void appenedSqlMessage(std::shared_ptr<FetchDBDataMessage> pMsg);

    void startSQL();

    void stopSQL();

signals:

protected:
    void start(Priority = InheritPriority);
protected:
    void run() override;

    bool execSQL(std::shared_ptr<FetchDBDataMessage> pMsg);

private:
    internal::FetchDBDataPrivate* _d{nullptr};
    friend class internal::FetchDBDataPrivate;

};
}
}
#endif // FETCHDBDATA_H

           

循环等待新的sql申请,并执行sql语句,执行结果通过协议体中的回调函数返回。

//fetchdbdata.cpp
#include "fetchdbdata.h"
#include <QList>
#include <QMutex>
#include <QDebug>
#include <QWaitCondition>

using namespace libra;
using namespace libra::adapter;

namespace libra {
namespace adapter {
namespace internal {
const int MAX_WAIT_TIME = 2000;
class FetchDBDataPrivate{
public:
    FetchDBDataPrivate(){}
    ~FetchDBDataPrivate(){}
    QList<std::shared_ptr<FetchDBDataMessage>> m_sqlMessageList;
    QMutex m_mtxSqlMessages;
    QWaitCondition m_wcSqlMessages;
    bool m_isStoped{false};
};
}
}
}

FetchDBData::FetchDBData(QObject *parent)
    : QThread{parent}
    , _d(new internal::FetchDBDataPrivate())
{

}

FetchDBData::~FetchDBData()
{
    if(_d)
    {
        delete _d;
        _d = nullptr;
    }
}

void FetchDBData::appenedSqlMessage(std::shared_ptr<FetchDBDataMessage> pMsg)
{
    QMutexLocker locker(&_d->m_mtxSqlMessages);
    _d->m_sqlMessageList.push_back(pMsg);
    _d->m_wcSqlMessages.wakeAll();
}

void FetchDBData::startSQL()
{
    _d->m_isStoped = false;
    FetchDBData::start();
}

void FetchDBData::stopSQL()
{
    while (isRunning()){
        QMutexLocker locker(&_d->m_mtxSqlMessages);
        _d->m_isStoped = true;
        _d->m_wcSqlMessages.wakeAll();
    }
}

void FetchDBData::start(Priority p)
{
    QThread::start(p);
}

void FetchDBData::run()
{
    while(!_d->m_isStoped)
    {
        QList<std::shared_ptr<FetchDBDataMessage>> msgList;
        QMutexLocker locker(&_d->m_mtxSqlMessages);
        if(_d->m_sqlMessageList.isEmpty())
        {
            _d->m_wcSqlMessages.wait(&_d->m_mtxSqlMessages, internal::MAX_WAIT_TIME);
            if(_d->m_sqlMessageList.isEmpty())
            {
                std::swap(msgList, _d->m_sqlMessageList);
                _d->m_sqlMessageList.clear();
            }
        }
        else
        {
            std::swap(msgList, _d->m_sqlMessageList);
            _d->m_sqlMessageList.clear();

        }
        locker.unlock();
        if(msgList.isEmpty())
        {
            continue;
        }

        while (!msgList.isEmpty()) {
            std::shared_ptr<FetchDBDataMessage> pMsg = msgList.takeFirst();
            if(!execSQL(pMsg))
            {
                qWarning() <<"execSQL Fail!";
            }
        }
    }
}

bool FetchDBData::execSQL(std::shared_ptr<FetchDBDataMessage> pMsg)
{
    QThread::msleep(1000);   //模拟查数据耗时
    QList<QStringList> dbDataList;
    if(FetchDBDataMessage::FetchDBDataMessage::Fetch_Type::opt_select == pMsg->type)
    {
        //构造假数据
        for(int i=0; i<10; i++)
        {
            QStringList data;
            data<<QString("查询成功");
            data<<QString("%1").arg(i);
            data <<":";
            data <<"data-data-data";
            dbDataList.push_back(data);
        }
    }else if(FetchDBDataMessage::FetchDBDataMessage::Fetch_Type::opt_insert == pMsg->type){
        QStringList data;
        data<<QString("插入成功");
        dbDataList.push_back(data);

    }else if(FetchDBDataMessage::FetchDBDataMessage::Fetch_Type::opt_delete == pMsg->type){
        QStringList data;
        data<<QString("删除成功");
        dbDataList.push_back(data);

    }else if(FetchDBDataMessage::FetchDBDataMessage::Fetch_Type::opt_update == pMsg->type){
        QStringList data;
        data<<QString("更新成功");
        dbDataList.push_back(data);
    }else{
        qCritical() << "unkonwn sql opt!";
        return false;
    }

    if(!pMsg->_func)
    {
        qCritical() <<"_func is nullptr!";
        return false;
    }
    //通知外层查询结果
    pMsg->_func(dbDataList);
    return true;
}
           

3、对外提供的单例类,业务代码通过构造协议消息体 FetchDBDataMessage,进行execSql调用,并在回调函数中等待执行结果。

//fetchdatamananger.h
#ifndef FETCHDATAMANANGER_H
#define FETCHDATAMANANGER_H

#include <QObject>
#include <memory>
#include "fetchdbdatamessage.h"

namespace libra {
namespace adapter {
namespace internal {
class FetchDataManangerPrivate;
}
class FetchDataMananger : public QObject
{
    Q_OBJECT
public:
    static FetchDataMananger* getInstnce();
    static releaseInstance();
    void init();
    void uninit();
    void execSQL(std::shared_ptr<FetchDBDataMessage> pSql);
private:
    explicit FetchDataMananger(QObject *parent = nullptr);
    ~FetchDataMananger();

signals:
private:
    internal::FetchDataManangerPrivate* _d{nullptr};
    friend class internal::FetchDataManangerPrivate;
};
}
}
#endif // FETCHDATAMANANGER_H
           
//fetchdatamananger.cpp
#include "fetchdatamananger.h"
#include "fetchdbdata.h"

namespace libra {
namespace adapter {
namespace internal {
FetchDataMananger* pFetchDataMananger = nullptr;
class FetchDataManangerPrivate
{
public:
    FetchDBData m_fetchData;
};
}

FetchDataMananger *FetchDataMananger::getInstnce()
{
    static std::once_flag s_flag;
    std::call_once(s_flag,
                   [](){internal::pFetchDataMananger = new FetchDataMananger();});
    return internal::pFetchDataMananger;
}

FetchDataMananger::releaseInstance()
{
    delete internal::pFetchDataMananger;
    internal::pFetchDataMananger = nullptr;
}

void FetchDataMananger::init()
{
    _d->m_fetchData.startSQL();
}

void FetchDataMananger::uninit()
{
    _d->m_fetchData.stopSQL();
}

void FetchDataMananger::execSQL(std::shared_ptr<FetchDBDataMessage> pSql)
{
    _d->m_fetchData.appenedSqlMessage(pSql);
}

FetchDataMananger::FetchDataMananger(QObject *parent)
    : QObject{parent}
    , _d(new internal::FetchDataManangerPrivate())
{

}

FetchDataMananger::~FetchDataMananger()
{
    if(internal::pFetchDataMananger)
    {
        delete internal::pFetchDataMananger;
        internal::pFetchDataMananger = nullptr;
    }

    if(_d)
    {
        delete _d;
        _d = nullptr;
    }
}
}
}
           

 4、以下是框架的测试代码。

#ifndef A_TEST_BUSINESS_H
#define A_TEST_BUSINESS_H

#include <QObject>

namespace libra {
namespace business{
namespace internal{
class A_TEST_BusinessPrivate;
}

class A_TEST_Business : public QObject
{
    Q_OBJECT
public:
    explicit A_TEST_Business(QObject *parent = nullptr);
    ~A_TEST_Business();
    //向数据库添加数据
    void addDataToDb();
    //从数据库删除数据
    void deleteDataFromDb();
    //更新数据库数据
    void updataDataFromDb();
     //从数据库查询数据
    void selectDataFromDb();
signals:

private:
    internal::A_TEST_BusinessPrivate* _d{nullptr};
    friend class internal::A_TEST_BusinessPrivate;
};
}
}
#endif // A_TEST_BUSINESS_H
           
#include "a_test_business.h"
#include "fetchdatamananger.h"
#include <QMutex>
#include <QDebug>

namespace libra {
namespace business {
namespace internal {
class A_TEST_BusinessPrivate
{
public:
    QMutex mx;
    QList<QStringList> data;
};
}
A_TEST_Business::A_TEST_Business(QObject *parent)
    : QObject{parent}
    , _d(new internal::A_TEST_BusinessPrivate())
{

}

A_TEST_Business::~A_TEST_Business()
{
    if(_d)
    {
        delete _d;
        _d = nullptr;
    }
}

void A_TEST_Business::addDataToDb()
{
    std::shared_ptr<FetchDBDataMessage> pSQL(new FetchDBDataMessage());
    pSQL->type = FetchDBDataMessage::Fetch_Type::opt_insert;
    pSQL->strSQL = QString("INSTER");
    pSQL->_func = [&](QList<QStringList> listResult){
        for (int i = 0; i < listResult.size(); ++i) {
            qInfo() <<listResult.at(i);
        }
        QMutexLocker locker(&_d->mx);
        _d->data = listResult;
    };
    libra::adapter::FetchDataMananger::getInstnce()->execSQL(pSQL);
}

void A_TEST_Business::deleteDataFromDb()
{
    std::shared_ptr<FetchDBDataMessage> pSQL(new FetchDBDataMessage());
    pSQL->type = FetchDBDataMessage::Fetch_Type::opt_delete;
    pSQL->strSQL = QString("delete");
    pSQL->_func = [&](QList<QStringList> listResult){
        for (int i = 0; i < listResult.size(); ++i) {
            qInfo() <<listResult.at(i);
        }
        QMutexLocker locker(&_d->mx);
        _d->data = listResult;
    };
    libra::adapter::FetchDataMananger::getInstnce()->execSQL(pSQL);
}

void A_TEST_Business::updataDataFromDb()
{
    std::shared_ptr<FetchDBDataMessage> pSQL(new FetchDBDataMessage());
    pSQL->type = FetchDBDataMessage::Fetch_Type::opt_update;
    pSQL->strSQL = QString("delete");
    pSQL->_func = [&](QList<QStringList> listResult){
        for (int i = 0; i < listResult.size(); ++i) {
            qInfo() <<listResult.at(i);
        }
        QMutexLocker locker(&_d->mx);
        _d->data = listResult;
    };
    libra::adapter::FetchDataMananger::getInstnce()->execSQL(pSQL);
}

void A_TEST_Business::selectDataFromDb()
{
    std::shared_ptr<FetchDBDataMessage> pSQL(new FetchDBDataMessage());
    pSQL->type = FetchDBDataMessage::Fetch_Type::opt_select;
    pSQL->strSQL = QString("SELECT * FROM t_test");
    pSQL->_func = [&](QList<QStringList> listResult){
        for (int i = 0; i < listResult.size(); ++i) {
            qInfo() <<listResult.at(i);
        }
        QMutexLocker locker(&_d->mx);
        _d->data = listResult;
    };
    libra::adapter::FetchDataMananger::getInstnce()->execSQL(pSQL);
}
}
}
           

循环进行数据申请。 

#include <QCoreApplication>
#include <memory>
#include <QDebug>
#include <QThread>
#include <QList>
#include <QStringList>
#include "fetchdatamananger.h"
#include "a_test_business.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    libra::adapter::FetchDataMananger::getInstnce()->init();

    int64_t count = 0;
    while (true) {
//        std::shared_ptr<FetchDBDataMessage> pSQL(new FetchDBDataMessage());
//        pSQL->type = FetchDBDataMessage::Fetch_Type::opt_select;
//        pSQL->strSQL = QString("SELECT * FROM t_test");
//        pSQL->_func = [&](QList<QStringList> listResult){
//            qInfo() <<"===================================================";
//            qInfo() <<"第"<<++count<<"次查询结果";
//            for (int i = 0; i < listResult.size(); ++i) {
//                qDebug() << listResult.at(i);
//            }
//            qInfo() <<"===================================================";
//        };

//        libra::adapter::FetchDataMananger::getInstnce()->execSQL(pSQL);
        libra::business::A_TEST_Business aTest;
        aTest.addDataToDb();
        aTest.deleteDataFromDb();
        aTest.updataDataFromDb();
        aTest.selectDataFromDb();
        QThread::msleep(2000);
    }

    libra::adapter::FetchDataMananger::getInstnce()->uninit();
    return a.exec();
}
           

继续阅读