Qt многопоточность в работе с БД

106
09 сентября 2019, 19:00

Появилось проблема в оптимизации приложения которая работает с БД(MySQL). Есть весьма большой SQL запрос(выборка с множеством inner join) который выполняется в конструкторе и на основе него строится UI. И ПО висит во время запроса, а это плохое поведение пользователи сейчас нервные приложение могут и закрыть... Я бы хотел перенести работу с БД в отдельный поток но к сожалению я не имел опыта в этом.

Можно ли минимально работающий пример работы много поточного приложения где один поток рисует UI и занимается бизнес логикой а другой работой с БД. А я бы оттолкнулся от этого примера и переписал бы свой. Спасибо за внимание.

Answer 1

Пример подобного кода можете посмотреть в моем гите: класс инкапсулирующий QSqlDatabase и предоставляющий шаблонные методы для вызова в другом потоке: тыц. Пример использования можете найти тут: тыц. Если вкратце, то нижеприведенная связка методов:

template <typename DB, typename Function , typename ...Args, typename CallBack, typename ReturnValue, typename ConnSetter>
    QUuid Database::callAsync(DB* db, ConnSetter&& setter, QFutureWatcher<ReturnValue>* watcher, Function&& query, CallBack&& callBack, Args&& ...args)
    {    
        auto id = prepareToAsyncCall(watcher, std::forward<CallBack>(callBack));
        QFuture<ReturnValue> futureValue
                = QtConcurrent::run(
                    bind(
                        exceptionWrapper <DB, ReturnValue, Function, ConnSetter, Args...>, id, watcher, db, forward<Function>(query), setter, forward<Args>(args)...));
        watcher->setFuture(futureValue);
        return id;
    }

    template <typename DB ,typename ReturnValue, typename Function ,typename ConnSetter, typename ...Args>
    auto Database::exceptionWrapper (QUuid id, QFutureWatcher<ReturnValue>* w, DB* db, Function function, ConnSetter setter, Args& ...args)
    -> decltype((db->*function)(args...))
    {
        try
        {
            QScopedPointer <DB> tempDbConn(new DB(id));
            setter(tempDbConn.data());
            QObject::connect(tempDbConn.data(), &Database::queryCanceled, tempDbConn.data(),
                             [w](){w->disconnect(); w->cancel();}, Qt::DirectConnection);
            db->setConnectionOptions(tempDbConn.data());
            return (tempDbConn.data()->*function)(args...);
        }
        catch (std::exception& e)
        {
            throw ThreadDbException(e);
        }
    }

Позволяет вызвать любой метод класса Database в потоке, получить результат через QFuture и если что вернуть в главный поток исключение. Если возникнут какие-либо вопросы, то можете написать мне на почту (она указана в профиле).

READ ALSO
QT C++ работа с базой данных в разных потоках

QT C++ работа с базой данных в разных потоках

Как можно модифицировать ПО для мультипоточной работы

107
Отличие между const string &amp;s и string &amp;s

Отличие между const string &s и string &s

столкнулся с одной проблемой, и не могу понять, почему так происходит

93
Как добавить большой список слов в вектор?

Как добавить большой список слов в вектор?

Нужно добавить большой список слов в вектор

112
sprintf - формирование нескольких подсрок с использованием одного параметра

sprintf - формирование нескольких подсрок с использованием одного параметра

Подскажите, можно ли реализовать следующую задумку:

91