Russian Qt Forum

Qt => Вопросы новичков => Тема начата: virtual_root от Август 20, 2012, 11:31



Название: Создание очереди запросов
Отправлено: virtual_root от Август 20, 2012, 11:31
Добрый день. Ребята, у меня возник вопрос, подскажите решение!
У меня есть БД, к которой из разных потоков могут обращаться классы и записывать, удалять и прочие функции выполнять с данными.
При множественной работе с БД, чтобы не возникло конфликтов, я так понимаю мне нужно использовать мьютексы и на время выполнения запроса блокировать БД, чтобы другой поток не мог ничего изменить во время выполнения запросов.
Я хочу создать какую-нибудь очередь запросов и выполнять их. Т.е. есть класс А работающий в потоке А и есть класс В работающий в потоке В. Они одновременно хотят выполнить разные запросы к БД, вызвав фунции InsertData() и DeleteData() из класса DataBase. Как мне сделать такую очередь чтобы в ней можно было в ней хранить вызовы функ-й InsertData() и DeleteData() и других от разных классов и по очереди выполнять эту функцию с разными запросами.
Это что-то вроде тех же сигналов и слотов, только как мне их так прикрутить к моей задаче?
Подскажите пожалуйста!)


Название: Re: Создание очереди запросов
Отправлено: Kurles от Август 20, 2012, 11:51
Дык сигналами и слотами и прикручивай.


Название: Re: Создание очереди запросов
Отправлено: Igors от Август 20, 2012, 12:39
Сигналы с типом коннекта QururdConnection и есть очередь (событий). Поручаете одной нитке обращаться к базе, а все остальные шлют ей такие сигналы - вот и все. Также нужно поинтересоваться - если Ваша СУБД multi-threaded то необходимости в этом нет


Название: Re: Создание очереди запросов
Отправлено: xokc от Август 20, 2012, 15:46
Речь идёт о многопользовательском доступе к СУБД или к её модели в Qt? Если о БД - то проблема должна решаться на её уровне (блокировки записей, страниц и т.п.). Иначе при работе, например, двух клиентских приложений одновременно - ничем тебя ни мьютексы, ни сигнал/слоты не спасут.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 21, 2012, 10:21
речь идет о модели. Т.е. у меня есть классы внутри одного приложения которые могут одновременно выполнять такие операции к бд как insert, update, delete. Насколько я знаю, то можно только один из такого рода запросов выполнить в единицу времени. А вот запросы select могут и параллельно обращаться. Получается что читать базу могут одновременно несколько потоков, а писать должен только один. И мне бы хотелось ни сигналы слать, чтобы добавить данные(я же как0то и данные должна передавать), а вызывать функцию которая выполняет запрос на добавление, но её вызовы, если их несколько одновременно - ложить в очередь и из неё выполнять, при этом возвращая результат вызвывшему классу или его методу.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 21, 2012, 10:29
Класс который работает напрямую с бд и выполняет запросы у меня сиглтон.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 21, 2012, 10:37
Как бы я хочу сделать так: если вызвана одна из трех функций:
Код
C++ (Qt)
 virtual DataBaseError UpdateData(QString TableName,QHash<QString, QVariant> data, QString condition);  // обновление одной записи
   virtual DataBaseError InsertData(QString TableName,QHash<QString, QVariant> data);  // добавление  записи
   virtual DataBaseError Delete(QString TableName, QString condition);
то полодить её вызов в очередь. А какая-нибудь внутренняя функция класса проверяет всё время очередь и если появились вызовы функций, то немедленно их поочереди исполняет. После исполнения эта функция должна вернуть результат, той функции которая запросила вызов одной из терх вышеуказанных функций. Т.о. получается функция X()  вызвала фун-ю InsertData(QString TableName,QHash<QString, QVariant> data); Вызов этой функции попал в очередь. А функция X() ждет пока вернется результат выполнения вызвынной функции.
Как мне заставить функцию ждать результат выполнения? И как положить вызовы в очередь? Что использовать в качестве очереди?


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 21, 2012, 11:11
я придумала как поступить для 3-х функций:
Код
C++ (Qt)
virtual DataBaseError UpdateData(QString TableName,QHash<QString, QVariant> data, QString condition);  // обновление одной записи
   virtual DataBaseError InsertData(QString TableName,QHash<QString, QVariant> data);  // добавление сразу нескольких запесей
   virtual DataBaseError Delete(QString TableName, QString condition);
они просто будут посылать сигнал с параметром функции ExecQuery(QString). В качетве параметра будут передавать запрос.
Поскольку запросы типа insert, update и delete не требуют возвращающего значения(набора записей) то такой вариант мне подходит. Но как быть с запросами select ведь мне нужно дождаться возвращающего занчения изтой функции которая вышлет сигнал. Как такое сделать?


Название: Re: Создание очереди запросов
Отправлено: Igors от Август 21, 2012, 11:58
Поскольку запросы типа insert, update и delete не требуют возвращающего значения(набора записей) то такой вариант мне подходит. Но как быть с запросами select ведь мне нужно дождаться возвращающего занчения изтой функции которая вышлет сигнал. Как такое сделать?
Можно создать свою очередь напр используя QList. Но неясно чего Вы хотите, ведь полученные результаты select могут уже ничему не соответствовать  если потом было insert/delete. Это нужно решать на уровне посылающих, т.е. не обновлять базу пока чтение не закончено, возможно используя QReadWriteLock


Название: Re: Создание очереди запросов
Отправлено: trot от Август 21, 2012, 13:22
Можно поинтересоваться, что у вас за приложение, кто или что будет вызывать запросы в базу данных. Зачем нужна необходимость выполнять запросы в отдельных потоках. Эти потоки замыкаются на отдельное соединение с БД или вы еще для каждого потока создаете свое соединение с БД.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 22, 2012, 10:59
Я пишу класс который будет использоваться в приложении во многих других классах и они в свою очередь будут через него выполнять запросы к бд. Некоторые из классов которые будут работать с моим классом( а мне не известно какие, просто дали задачу разработать определенный класс) будут работать в отдельных потоках.
У меня ещё пару вопросов появилось:
а можно сделать несколько соединений с одной и той же БД ? Как?
еще раз вызвать метод QSqlDatabase::open() ?
И как можно сделать сигнал приватным? Чтобы его мог использовать только сам класс. Это мне для очереди надо)
Ребят, подскажите пожалуйста.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 22, 2012, 11:25
Ребята, я правильно понимаю: если у меня один и тот же сигнал просигналил в разных потоках одновременно, то слот на него подписанный исполнится поочередно? Т.е. сначала обработает один сигнал, а потом другой? Не сразу в двух потока, произойдет исполнение слота?
соединяю так:
Код:
connect(this,SIGNAL(_execQuery(QString)),this,SLOT(ExecQuery(QString)),Qt::QueuedConnection);

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


Название: Re: Создание очереди запросов
Отправлено: Igors от Август 22, 2012, 11:32
Ребята, я правильно понимаю: если у меня один и тот же сигнал просигналил в разных потоках одновременно, то слот на него подписанный исполнится поочередно? Т.е. сначала обработает один сигнал, а потом другой? Не сразу в двух потока, произойдет исполнение слота?
соединяю так:
Код:
connect(this,SIGNAL(_execQuery(QString)),this,SLOT(ExecQuery(QString)),Qt::QueuedConnection);

Ведь по логики слот обрабатывается в том потоке в котором был издан сигнал. А у меня предположим сигнал был издан в двух потоках, то как тогда поведет себя слот?
Нет, смысл QueuedConnection в том что слот будет вызван в той нитке где он живет (по умолчанию - где был создан, можно установить с помощью moveToThread). Поэтому порядок срабатывания слотов может быть любым и меняться от одного выполнения до другого.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 22, 2012, 11:45
Тогда в моей ситуации это поможет?
Код
C++ (Qt)
void PQInterfaceFunctionPostgreSQL::ExecQuery(QString str){
 
   str.left(str.indexOf(';'));   // для обеспечения безопасности обрежим строку до символа ;
 
   if (!_db.isOpen()) emit Error(DataBaseNoOpen);
   else {
       QMutexLocker lock(_mutex);   // мы блокируем кусок кода поле этой строки пока объект lock не будет уничтожен
       QSqlQuery query(_db);
       if (!query.exec(str)) emit Error(SQLEror);
   }
 
}

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


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 22, 2012, 11:47
или мне нужно что-то дописать чтобы параллельно вызванный слот дождался разблокировки а потом выполнился? И если я изменю слот на обычную функцию, что надо дописать чтобы она дождалась разблокировки мьютекса и продолжила своё выполнение?


Название: Re: Создание очереди запросов
Отправлено: trot от Август 22, 2012, 15:24
Цитировать
Я пишу класс который будет использоваться в приложении во многих других классах и они в свою очередь будут через него выполнять запросы к бд. Некоторые из классов которые будут работать с моим классом( а мне не известно какие, просто дали задачу разработать определенный класс) будут работать в отдельных потоках.
Мне кажется вам надо разработать однопоточный класс с одним соединением с БД. Это не помешает использовать ваш класс во многих потоках.
Иначе для вашего каждого потока потребуется создавать отдельное соединение с БД, а если будете замыкать все потоки на одно соединение, то пропадает смысл в многопоточности, т.к. в рамках одного соединения запросы выполняются последовательно.


Название: Re: Создание очереди запросов
Отправлено: virtual_root от Август 22, 2012, 15:32
спасибо!