Russian Qt Forum
Апрель 29, 2024, 03:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Threads and the SQL Module  (Прочитано 13052 раз)
CuteBunny
Гость
« : Июнь 22, 2012, 16:45 »

Не понятки с QSqlDatabase...

Цитировать
A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

У меня простенькая задача: необходимо "проверять" таблицу на новые строки - я создал отдельный поток через QObject & moveToThread(), в котором по timerEvent'у делаю запрос и проверяю текущее кол-во строк, с тем что выдает запрос.

Так вот, решил я не создавать никаких соединений в рабочем потоке... Я ожидал сообщения в output'е "database not open" или еще что-нибудь плохое, но все работает, либо я просто не понимаю, что значит "A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.", либо где-то я не правильно что-то делаю???

В гуи первый запрос был вида: select count([id]) from [orders], его же я и использовал в рабочем потоке...

В том, что поток у меня отдельно работает от гуи-потока я проверял, ставил цикл forever в timerEvent хендлере, гуи работает как часы, не зависая...

Думал, что дефолтное подключение, особое, решил в гуи потоке дать имя подключению, в рабочем потоке его же и использую - результат работает...

Думал, что драйвер QODBC хитрый - попробовал на QSQLITE - работает...

Пробовал и через QThreadPool и QRunnable...

Запросы - только селекты были...
Записан
Bepec
Гость
« Ответ #1 : Июнь 22, 2012, 16:49 »

Не понял вопроса. Слишком расплывчато и непонятно, что вы пытаетесь сделать.

Если всё работает и ошибок в консоле нет - всё прекрасно.
Записан
CuteBunny
Гость
« Ответ #2 : Июнь 22, 2012, 16:53 »

Я попытался сделать то, что теоретически not supported:

Создал в гуи(основном) потоке дефолтное соединение с бд, создал отдельно поток и в нем через QSqlQuery выполнил запрос, при чем не указал, какое соединение я использовал, т.е. использовалось дефолтное и все работает.

Меня это просто настораживает...
Записан
Bepec
Гость
« Ответ #3 : Июнь 22, 2012, 17:55 »

Какой ide пользуешься? Если QtCreator - то я не смогу тебе подсказать, как точно определить, где выполняется запрос Улыбающийся

Ничего без кода сказать нельзя, но... % 90 что у тебя запрос происходит в том потоке, в котором создано соединение Улыбающийся Другой вопрос, почему ты думаешь, что оно используется в другом потоке Веселый
Записан
CuteBunny
Гость
« Ответ #4 : Июнь 22, 2012, 18:43 »

IDE - vs2010...

Код:
#ifndef STORE_H
#define STORE_H

#include <QtGui/QDialog>
#include "ui_store.h"

class QThread;
class threadobj;

class store : public QDialog
{
Q_OBJECT

public:
store(QWidget *parent = 0, Qt::WFlags flags = 0);
~store();

private:
Ui::storeClass ui;
QThread *m_thread;
threadobj *m_obj;
};

#include "store.h"

#include "threadobj.h"

#include <QSqlDatabase>
#include <QThread>

store::store(QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags)
{
ui.setupUi(this);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("test.sqlite");
db.open();
m_thread = new QThread;
m_obj = new threadobj;
m_obj->moveToThread(m_thread);
connect(m_thread, SIGNAL(started()), m_obj, SLOT(checkTable()));
connect(m_obj, SIGNAL(finished()), m_thread, SLOT(quit()));
m_thread->start();
}

store::~store()
{
if (m_thread->isRunning()) {
m_thread->quit();
m_thread->wait();
}
QSqlDatabase db = QSqlDatabase::database();
db.close();
}


#endif // STORE_H


Код:
#ifndef THREADOBJ_H
#define THREADOBJ_H

#include <QObject>

class threadobj : public QObject
{
Q_OBJECT

public:
threadobj(QObject *parent = 0);
~threadobj();
public slots:
void checkTable();
signals:
void finished();
};

#endif // THREADOBJ_H


#include "threadobj.h"

#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>

#include <QDebug>

threadobj::threadobj(QObject *parent)
: QObject(parent)
{

}

threadobj::~threadobj()
{

}

void threadobj::checkTable()
{
QSqlQuery q;
if (!q.exec("select count(id) from orders")) {
qDebug() << q.lastError().text();
} else {
q.first();
int c = q.value(0).toInt();
qDebug() << c;
}
emit finished();
}
Записан
mutineer
Гость
« Ответ #5 : Июнь 22, 2012, 19:14 »

А кто будет удалять m_thread и m_obj?Улыбающийся
Записан
DmitryM
Гость
« Ответ #6 : Июнь 26, 2012, 10:09 »

У тебя select из-за count отрабатывается быстро.

Записан
CuteBunny
Гость
« Ответ #7 : Июнь 29, 2012, 09:16 »

А кто будет удалять m_thread и m_obj?Улыбающийся

Да, удалять нужно - не спорю... Но суть все равно в том, что для QSqlQuery, получается, необязательно создавать отдельное соединение в потоке, на сколько я понял.

Еще я попробовал сделать много инсертов в том же потоке, соединение у меня было заблокировано и модель в основном потоке стала тупить.
Записан
DmitryM
Гость
« Ответ #8 : Июнь 29, 2012, 09:49 »

Да, удалять нужно - не спорю... Но суть все равно в том, что для QSqlQuery, получается, необязательно создавать отдельное соединение в потоке, на сколько я понял.

Еще я попробовал сделать много инсертов в том же потоке, соединение у меня было заблокировано и модель в основном потоке стала тупить.
Это не модель тупит, это поток в котором было создано подключение заблокирован, на время работы с подключением в другом потоке.
Записан
vregess
Гость
« Ответ #9 : Июнь 30, 2012, 12:27 »

Да, удалять нужно - не спорю... Но суть все равно в том, что для QSqlQuery, получается, необязательно создавать отдельное соединение в потоке, на сколько я понял.

Потоки такая штука.. однажды может вылезти проблема.
Для уверенности попробуй вставить

Код
C++ (Qt)
qDebug() << QThread::currentThreadId();

в threadobj::checkTable() и store::store().

Сразу станет ясно, что откуда вызывается.
Записан
vregess
Гость
« Ответ #10 : Июнь 30, 2012, 12:46 »

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

И еще про sqlite. Там есть 3 варианта работы с потоками: Single-thread, Multi-thread и Serialized.
У тебя по умолчанию может стоять Serialized, у которого меньше всего ограничений для работы в многопоточной среде.
Тут подробности: http://www.sqlite.org/threadsafe.html
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #11 : Июль 02, 2012, 10:12 »

Кстати, возможно проблемы не вылазят, тк ты используешь подключение только в потоке.
Попробуй в главном и дочернем потоке поюзать одно подключение.
Скорее всего дело именно в этом.
Записан
kostya2vntu
Гость
« Ответ #12 : Июль 02, 2012, 18:03 »

Подобная дискуссия была когда-то на StackOverflow: http://stackoverflow.com/questions/7566949/qsql-module-and-multithreaded-application
Цитирую:
Цитировать
Your QSqlQuery object knows nothing about the QSqlDatabase you also created because you're not using the "db connected" constructor QSqlQuery::QSqlQuery(QString&, QSqlDatabase) (i.e. you don't pass the pre-created db to the query). The way you instantiate the query means that a new, separate DB connection will be created/torn down each time req() is called. Which is thread-safe, but potentially expensive. – FrankH. Sep 27 '11 at 11:45
Если коротко: у тебя в потоке создается новое подключение.
Записан
vregess
Гость
« Ответ #13 : Июль 02, 2012, 22:08 »

Хм, не знал.
В документации про такое поведение не сказано.

Цитировать
QSqlQuery::QSqlQuery ( const QString & query = QString(), QSqlDatabase db = QSqlDatabase() )

Constructs a QSqlQuery object using the SQL query and the database db. If db is not specified, or is invalid, the application's default database is used. If query is not an empty string, it will be executed.

Наверное там внутри используется QSqlDatabase::cloneDatabase(), если affinity не совпадают.. хз.
Записан
kostya2vntu
Гость
« Ответ #14 : Июль 03, 2012, 01:52 »

Завтра посмотрю что там внутри, самому интересно стало. А пока, насколько я понял, под подключением имеется ввиду конкретный обьект QSqlDatabase.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.073 секунд. Запросов: 22.