Название: Решено: Результаты Mysql запросов и многопоточность приложения
Отправлено: soiam от Апрель 11, 2013, 10:54
Изначально создал класс для работы с БД mysql в потоке, в котором вертится gui. Но увидел недостатки этого: тормоза gui, при отсутствии коннекта мертвые подвисания. И решил перевести работу с БД в отдельный QThread. Создал объект БД в функции run QThread, завел сингалы созданного QThread на слоты БД(для создания подключения, для формирования запроса, команды).
Вопрос в следующем, как мне считать результаты запросов БД по требованию из потока, в котором вертится GUI? Все результаты содержаться в QSqlQuery, который находится в другом потоке.
Название: Re: Результаты Mysql запросов и многопоточность приложения
Отправлено: mutineer от Апрель 11, 2013, 11:13
Кода бы...
Название: Re: Результаты Mysql запросов и многопоточность
Отправлено: soiam от Апрель 11, 2013, 11:29
Класс QThread class QDatabase_Manager : public QThread { public: //подготовить и послать команду SQL bool prepexec(const QString & query_cmd, QList<QNero_DataBase::QUERY_PARAM_T> * params = NULL,bool gen_sig = true,bool remote_mode = true);
......... private: QNero_DataBase * nero_db; }
//Создание обхекта БД и подключение слотов void QDatabase_Manager::run(void) { nero_db = new QNero_DataBase(); connect(this,SIGNAL(signal_connect(bool,QString,QString,QString)),nero_db,SLOT(slot_connect(bool,QString,QString,QString)),Qt::QueuedConnection); connect(this,SIGNAL(signal_disconnect(bool)),nero_db,SLOT(slot_disconnect(bool))); connect(this,SIGNAL(signal_exec(QString,QList<QNero_DataBase::QUERY_PARAM_T>*,bool,bool)),nero_db,SLOT(slot_exec(QString,QList<QNero_DataBase::QUERY_PARAM_T>*,bool,bool)),Qt::QueuedConnection); connect(nero_db,SIGNAL(signal_write_log(QString)),this,SIGNAL(signal_write_log(QString)),Qt::QueuedConnection); connect(nero_db,SIGNAL(signal_set_connected(bool,bool)),this,SLOT(slot_connected(bool,bool)),Qt::QueuedConnection); connect(nero_db,SIGNAL(signal_set_done(bool)),this,SLOT(slot_set_done(bool)),Qt::QueuedConnection); QThread::exec(); ........ delete nero_db; }
//функция подготовки команды запроса(query_cmd) и ее параметров(params, если они есть) к отправке в sql(удаленная mysql по умолчанию) void QDatabase_Manager::prepexec(const QString & query_cmd, QList<QNero_DataBase::QUERY_PARAM_T> * params,bool gen_sig, bool remote_mode) { done = false; data_error = false; emit signal_exec(query_cmd,params,gen_sig,remote_mode); while (!done) QApplication::processEvents();
if (!data_error) return true; else return false; }
//слот обработки ответа от sql void QDatabase_Manager::slot_set_done(bool error) { done = true; data_error = error; }
Класс БД class QNero_DataBase : public QObject { Q_OBJECT public: ...... signals:
void signal_set_connected(bool remote,bool value); void signal_set_done(bool data_error); public slots: ....... //подготовить и послать команду SQL bool slot_exec(const QString & query_cmd, QList<QNero_DataBase::QUERY_PARAM_T> * params = NULL,bool gen_sig = true,bool remote_mode = true); private: QSqlDatabase local_db,remote_db;//локальная и удаленная базы данных bool remote_transaction;//текущая транзакция к удаленной БД? QSqlQuery * local_query,* remote_query; QSqlRecord record; };
//подготовить и послать команду SQL bool QNero_DataBase::slot_exec(const QString & query_cmd, QList<QNero_DataBase::QUERY_PARAM_T> * params,bool gen_sig,bool remote_mode) { //подготовка команды
remote_query -> clear(); remote_query -> prepare(query_cmd); if (params != NULL) for (int i = 0; i < params -> count(); i++) remote_query -> bindValue(params -> at(i).key,params -> at(i).value);
//отправка if (!remote_query -> exec()) { emit signal_set_done(true);//отправляем сигнал о том, что транзакция с БД завершена с ошибкой return false; } emit signal_set_done(false);//отправляем сигнал о том, что транзакция с БД завершена record = remote_query -> record();
return true; }
Название: Re: Результаты Mysql запросов и многопоточность приложения
Отправлено: Bepec от Апрель 11, 2013, 12:00
Не понимаю проблемы. Ладно, если много записей, то сигналами лучше не посылать.
Но чем не угодила просто посылка сигнала "всё готово" и вызов функции, защищённой мутексами, возвращающей результаты?
PS прошу простить, если не понял смысла вопроса.
Название: Re: Результаты Mysql запросов и многопоточность приложения
Отправлено: soiam от Апрель 11, 2013, 12:12
Сразу так и сделал, сделал прямой вызов next() и value() //переход к следующей записи, возвращает true, если запись есть bool QDatabase_Manager::next() { return nero_db -> next(); }
//получение значение колонки column текущей записи QVariant QDatabase_Manager::value(const QString & column) { return nero_db -> value(column); } //переход к следующей записи, возвращает true, если запись есть bool QNero_DataBase::next() { return remote_query -> next(); }
//получение значение колонки column текущей записи QVariant QNero_DataBase::value(const QString & column) { return remote_query -> value(record.indexOf(column)); } Мютексы пока что не вводил так как операции с БД последовательны по коду лог Qtcreatora часто начал выдавать QSqlQuery::value: not positioned on a valid record, хотя частично данные читаются из QSqlQuery Кроме этого программа вываливается на случайной транзакции на строчке return remote_query -> value(record.indexOf(column)); (причем если идти по стеку функций вверх, то этот столбец не первый по счету в извлечении, т.е. до него другие столбцы извлекались нормально). Подумал, что это из-за того, что я обращаюсь к объекту в другом потоке минуя сигналы-слоты...
Название: Re: Результаты Mysql запросов и многопоточность приложения
Отправлено: Bepec от Апрель 11, 2013, 12:55
А тупо выдирать записи в список и передавать списком не пробовали?
А то как мне кажется, передавать запрос, чтобы потом тянуть информацию из него несколько затратно.
Название: Re: Результаты Mysql запросов и многопоточность приложения
Отправлено: soiam от Апрель 11, 2013, 13:11
Решил проблему. не успевал устанавливаться record. После посылки сигнала происходило быстрое переключение на другой поток, в котором начиналось извлечение данных(отработка слота, что всё хорошо) с помощью next и value. А так как record не был корректно установлен, он хранил значения от предыдущей транзакции. emit signal_set_done(false);//отправляем сигнал о том, что транзакция с БД завершена record = remote_query -> record();
Соответственно имена столбцов у транзакций не совпадали и программа на remote_query -> value(record.indexOf(column)) падала, так как record.indexOf(column) = -1 Всем спасибо за помощь!
|