Russian Qt Forum

Qt => Базы данных => Тема начата: CuteBunny от Июнь 22, 2012, 16:45



Название: Threads and the SQL Module
Отправлено: 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...

Запросы - только селекты были...


Название: Re: Threads and the SQL Module
Отправлено: Bepec от Июнь 22, 2012, 16:49
Не понял вопроса. Слишком расплывчато и непонятно, что вы пытаетесь сделать.

Если всё работает и ошибок в консоле нет - всё прекрасно.


Название: Re: Threads and the SQL Module
Отправлено: CuteBunny от Июнь 22, 2012, 16:53
Я попытался сделать то, что теоретически not supported:

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

Меня это просто настораживает...


Название: Re: Threads and the SQL Module
Отправлено: Bepec от Июнь 22, 2012, 17:55
Какой ide пользуешься? Если QtCreator - то я не смогу тебе подсказать, как точно определить, где выполняется запрос :)

Ничего без кода сказать нельзя, но... % 90 что у тебя запрос происходит в том потоке, в котором создано соединение :) Другой вопрос, почему ты думаешь, что оно используется в другом потоке :D


Название: Re: Threads and the SQL Module
Отправлено: CuteBunny от Июнь 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();
}


Название: Re: Threads and the SQL Module
Отправлено: mutineer от Июнь 22, 2012, 19:14
А кто будет удалять m_thread и m_obj?:)


Название: Re: Threads and the SQL Module
Отправлено: DmitryM от Июнь 26, 2012, 10:09
У тебя select из-за count отрабатывается быстро.



Название: Re: Threads and the SQL Module
Отправлено: CuteBunny от Июнь 29, 2012, 09:16
А кто будет удалять m_thread и m_obj?:)

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

Еще я попробовал сделать много инсертов в том же потоке, соединение у меня было заблокировано и модель в основном потоке стала тупить.


Название: Re: Threads and the SQL Module
Отправлено: DmitryM от Июнь 29, 2012, 09:49
Да, удалять нужно - не спорю... Но суть все равно в том, что для QSqlQuery, получается, необязательно создавать отдельное соединение в потоке, на сколько я понял.

Еще я попробовал сделать много инсертов в том же потоке, соединение у меня было заблокировано и модель в основном потоке стала тупить.
Это не модель тупит, это поток в котором было создано подключение заблокирован, на время работы с подключением в другом потоке.


Название: Re: Threads and the SQL Module
Отправлено: vregess от Июнь 30, 2012, 12:27
Да, удалять нужно - не спорю... Но суть все равно в том, что для QSqlQuery, получается, необязательно создавать отдельное соединение в потоке, на сколько я понял.

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

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

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

Сразу станет ясно, что откуда вызывается.


Название: Re: Threads and the SQL Module
Отправлено: vregess от Июнь 30, 2012, 12:46
Кстати, возможно проблемы не вылазят, тк ты используешь подключение только в потоке.
Попробуй в главном и дочернем потоке поюзать одно подключение.

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


Название: Re: Threads and the SQL Module
Отправлено: xokc от Июль 02, 2012, 10:12
Кстати, возможно проблемы не вылазят, тк ты используешь подключение только в потоке.
Попробуй в главном и дочернем потоке поюзать одно подключение.
Скорее всего дело именно в этом.


Название: Re: Threads and the SQL Module
Отправлено: kostya2vntu от Июль 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
Если коротко: у тебя в потоке создается новое подключение.


Название: Re: Threads and the SQL Module
Отправлено: vregess от Июль 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 не совпадают.. хз.


Название: Re: Threads and the SQL Module
Отправлено: kostya2vntu от Июль 03, 2012, 01:52
Завтра посмотрю что там внутри, самому интересно стало. А пока, насколько я понял, под подключением имеется ввиду конкретный обьект QSqlDatabase.


Название: Re: Threads and the SQL Module
Отправлено: TaIRou от Июль 24, 2012, 18:29
Ребят, появились у кого мысли по поводу использования одного соединения в нескольких потоках?
До какого момента это еще не критично?


Название: Re: Threads and the SQL Module
Отправлено: Alex_C от Июль 24, 2012, 22:33
Появились, причем совершенно случайно. Хотя это мне еще предстоит.
1. QSqlQuery - действительно пока непонятным образом подсоединяется к QSqlDatabase - делает ли он отдельное (clone) соединение или как еще - не понятно.
2. Одно соединение в нескольких потоках я 2 месяца пытался делать в своей проге на Дельфи. В принципе - работает. Но до возникновения конфликтов. Возникает вопрос - а почему не сделать несколько коннектов?  иУ меня была конкретная причина, почему я одно соединение пытался использовать.


Название: Re: Threads and the SQL Module
Отправлено: Nidxogg от Сентябрь 17, 2014, 21:25
Апну тему, может быть у кого-то появилось больше информации по этому поводу

P.S
Есть класс, который переносится в отдельный поток с помощью movetothread. В нем производится подключение к БД.
Соединение явно для запросов не указываю и они нормально работают как в гуи потоке, так и во втором потоке.

Как это все работает и каких подводных камней можно ждать? ???


Название: Re: Threads and the SQL Module
Отправлено: OKTA от Сентябрь 17, 2014, 22:48
Делал приложение и как-то даже не задумывался - сделал класс для бд, который насиловали потоки всяческие и ни разу не было ничего плохого на удивление. И от этого даже не задумывался, как там бд живется с одним соединением  :)


Название: Re: Threads and the SQL Module
Отправлено: Bepec от Сентябрь 17, 2014, 22:51
++ никаких проблем не замечено.