crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> QSqlDatabase в отдельном потоке, QSqlDatabase в отдельном потоке которому передаются запросы на выполн.
Гость_Sterr_*
сообщение 12.4.2009, 12:51
Сообщение #1





Гости








    


Есть gui приложение работающее с базой. Пытаюсь сделать так, чтобы вся работа с базой была выделена в отдельном потоке. После того как поток запущен ему будет передаваться через сигнал-слот указатель на класс Command, который наследуется остальными классами инкапсулирующими специфику команды. Набросал макет:

CODE
class Database : public QThread
{
private:
    QSqlDatabase *db;

public:
    Database();
    ~Database();
    
    void run();
    void initDatabase(QString user, QString pass);

public slots:
    void sqlExec(Command *);
    
};


CODE
Database::Database()
{
    
}

void Database::run()
{
    db =new QSqlDatabase::addDatabase("QPSQL");
    db->setHostName("192.168.1.2");
    db->setDatabaseName("dreamservice");
    db->setUserName("me");
    db->setPassword("123456");
    if(!db->open())
    {
        qDebug() << "Error opening bd";
    }
    this->exec();
}
void Database::sqlExec(Command *command)
{
    if(!command->start(db))
    {

    }
}

Database::~Database()
{

}




CODE
class Command : public QObject
{
    Q_OBJECT

public:
    Command();
    ~Command();

    virtual bool startCommand(QSqlDatabase *db);
};

class CommandRequestList : public Command
{
    Q_OBJECT

private:
    QSqlQuery *sqlQuery;

public:
    CommandRequestList();
    ~CommandRequestList();

    void setAttributes(int id);
    bool startCommand(QSqlDatabase *db);
};
CommandRequestList::CommandRequestList()
{

}
CommandRequestList::~CommandRequestList()
{

}

bool CommandRequestList::startCommand(QSqlDatabase *db)
{
    if (db != 0)
    {
        sqlQuery = new QSqlQuery(*db);
    
        QString query = "SELECT request.id_request, cl.company_name, agr.arg_service, request.status, request.tdate_create FROM repair_request request, agreement agr, client cl WHERE (request.id_agreement = agr.id_agr) AND (agr.id_client = cl.id_client)";
        if (!sqlQuery->exec(query))
        {
            QSqlError qwe = sqlQuery->lastError();
        }
        delete sqlQuery;
    }
    return true;
}



Вопросов 2:
1) db =new QSqlDatabase::addDatabase("QPSQL"); не работает =(( Я так понимаю что надо или разименование, или создавать объект? Но ведь для того чтобы он выполнялся в отдельном потоке он должен создаваться в секции run ??
2) Реально ли реализовать то что здесь описанно, в смысле.. правильном ли путём иду? Тоесть ещё раз если в кратце:
два потока - главный gui и поток работы с бд. Например при щелчке по форме с поиском вызывается слот который задаёт в соответствующий класс наследованный от Command нужные значения и высылает сигнал с указателем на этот класс. Этот сигнал соединяется со слотом из потока по работе бд sqlExex, в котором потом вызывается Command.startCommand(QSqlDatabase *db) внутри которого создаётся QSqlQuery и идёт вся работа запроса с базой.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 12.4.2009, 13:05
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Гость_Sterr_* @ 12.4.2009, 16:51) *
db =new QSqlDatabase::addDatabase("QPSQL");
а откуда вообще такая запись взялась (оператор new)? см. Асистент, как создавать новое соединение, как использовать имеющееся.

Цитата(Гость_Sterr_* @ 12.4.2009, 16:51) *
Реально ли реализовать то что здесь описанно,
да, оговорки смотри здесь Потоки и модуль SQL
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_Sterr_*
сообщение 12.4.2009, 13:08
Сообщение #3





Гости








    


Цитата
db = new QSqlDatabase();
db->addDatabase("QPSQL");


что-то я туплю с утра чуток=( не знаю почему меня addDatabase смутил..

А как быть в остальном на ваш взгляд?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_Sterr_*
сообщение 12.4.2009, 13:12
Сообщение #4





Гости








    


Фразу
"Соединение может использоваться только внутри создавшего его потока. Перемещение соединений между потоками и создание запросов в другой поток не поддерживается.

Кроме того, используемые драйверами QSqlDriver сторонние библиотеки могут наложить дополнительные ограничения на использование модуля SQL в многопоточной программе. За дополнительной информацией обращайтесь к руководству по клиенту вашей базы данных."

Я читал но не совсем понимаю.. Набросок команды

bool CommandRequestList::startCommand(QSqlDatabase *db)
{
    if (db != 0)
    {
        sqlQuery = new QSqlQuery(*db);
    
        QString query = "SELECT request.id_request, cl.company_name, agr.arg_service, request.status, request.tdate_create FROM repair_request request, agreement agr, client cl WHERE (request.id_agreement = agr.id_agr) AND (agr.id_client = cl.id_client)";
        if (!sqlQuery->exec(query))
        {
            QSqlError qwe = sqlQuery->lastError();
        }
        delete sqlQuery;
    }
    return true;
}

Ведь вызывается в потоке бд и следовательно работать должен...
Вообще я хотел именно спросить совета в плане проектного решения будет ли это работать и есть ли хорошие альтернативы..
Причина редактирования: используй тэг code
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 12.4.2009, 13:21
Сообщение #5


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


QSqlDatabase::addDatabase("QPSQL"); не возвращает ссылку.

В потоке создаешь соединение:
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");

и затем это соединение используешь в этом же потоке.
чтобы его использовать в другой функции этого же потока делаешь так:
QSqlDatabase db = QSqlDatabase::database();
QSqlQuery      q(db);
// пишешь свои запросы
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Гость_Sterr_*
сообщение 12.4.2009, 13:36
Сообщение #6





Гости








    


Если правильно вас понял то в run() создаю соединение QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL"); Как я понимаю даже после того как объект db уничтожен всё равно можно получить соединение бд в вспомогательной функции через QSqlDatabase db = QSqlDatabase::database(); ?
Спасибо!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 12.4.2009, 14:25
Сообщение #7


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Гость_Sterr_* @ 12.4.2009, 17:36) *
Как я понимаю даже после того как объект db уничтожен всё равно можно получить соединение бд в вспомогательной функции через QSqlDatabase db = QSqlDatabase::database(); ?
да. Правильнее этот класс было бы назвать QSqlConnection, т.к. описывает не БД а соединение с ней. Соединений в программе может быть несколько, в том числе и с одной БД.

При вызове статической функции QSqlDatabase::addDatabase("QPSQL"); в нутри этого класса создается соединение.
Этот класс необычный (ты невызываешь конструктор для создания объекта, а статическую функцию). Он подобен "Одиночке" (шаблон проектирования).
Этот вариант называется соеденение по умолчанию (без указания имени). А еще можно задать имя соединения. подробности в описании класса (у нас на сайте на русском языке)

П.С. наиболее употребительные классы модуля SQL создаются как обычные переменные, а не как указатели. И менно благодаря тому, что к соединению можно получить доступ из любого места программы, но незабыв про оговорку насчет потоков.
Если нужно получать доступ к одной и тойже БД из разных потоков, можно просто в каждом потоке создать по соединению ;)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
defnull
  опции профиля:
сообщение 18.4.2009, 21:12
Сообщение #8


Студент
*

Группа: Участник
Сообщений: 49
Регистрация: 1.5.2008
Пользователь №: 165

Спасибо сказали: 0 раз(а)




Репутация:   1  


Добрый день. Столкнулся с такой проблемой.. Есть поток DatabaseThread и класс Database, в котором находится QSqlDatabase. Для того чтобы работа шла параллельно Database создаётся именно в секции run и соотвественно до этого имеем просто указатель на Database. Но возникает проблема в том, что я не могу соединить слоты Database с объектами вне DatabaseThread до тех пор, пока не сработает метод run.. в результате получаю геморой в создании лишних слотов и сигналов для DatabaseThread. Как можно разрулить ситуацию? или проще вообще не заморачиваться над дополнительным потоком с базой ? (проект учебный в принципе, но хотелось быделать по уму)

з.ы. были мысли по поводу соединения сигнала с сигналом, но всё равно надо делать какую-то проверку на то что Database уже выделена память.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 18.4.2009, 21:27
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9666
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(defnull @ 19.4.2009, 1:12) *
Есть поток DatabaseThread и класс Database, в котором находится QSqlDatabase.
а для чего они так разделены? Почему не одним классом?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
defnull
  опции профиля:
сообщение 18.4.2009, 21:38
Сообщение #10


Студент
*

Группа: Участник
Сообщений: 49
Регистрация: 1.5.2008
Пользователь №: 165

Спасибо сказали: 0 раз(а)




Репутация:   1  


Цитата(Litkevich Yuriy @ 18.4.2009, 22:27) *
Цитата(defnull @ 19.4.2009, 1:12) *
Есть поток DatabaseThread и класс Database, в котором находится QSqlDatabase.
а для чего они так разделены? Почему не одним классом?


По причине того, что надо обрабатывать в потоке классы Command, в которых содержиться команда SQL и происходит запись и обработка данных. Таким образом Database исключительно обрабатывает ошибки с которыми не может справиться Command (переподключение к БД например) Можно было бы конечно QSqlDatabase наследовать классом Database, но всё равно остаётся проблемы, так как чтобы передавать этот класс Command от например Gui класса классу Database приходится идти через поток. =(

з.ы. Sterr и есть я, просто не со своего компа всё делал..

Сообщение отредактировал defnull - 18.4.2009, 21:39
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 3.3.2021, 9:34