Russian Qt Forum

Qt => Базы данных => Тема начата: Tritiy от Май 06, 2009, 13:15



Название: Ошибка не определяется.
Отправлено: Tritiy от Май 06, 2009, 13:15
Здравствуй, уважаемые!
Поможите кто чем можете.
Возникла такая задача, проверять соединение с сервером БД в процессе работы программы. А так-как с Qt общаюсь недавно решил спросить совета у вас.

Программу писал с помощью Qt 4.3.4, компилировал под Ubuntu 8.04, БД MySQL.
Подключение к БД c помощью класса QSqlDatabase осуществляется при запуске программы. Запросы осуществляются переменной класса QSqlQuery через каждые 30 секунд стабильно. Однако при возникновении нештатной ситуации (неполадки в сети, выключение увдаленного компьютера с сервером БД) и при формировании очередного запроса возникает ошибка, приводящая к тому, что дальнейшее общение с программой становится невозможным. C помощью qDebug() и lastError() сообщение об ошибке говорит о том, что в общем-то никакой ошибки не произошло, когда уже и обращаться-то не к чему (БД не доступна). А после выполнения QSqlQuery::exec() или QSqlQuery::isActive() деятельность программы совершенно приостанавливается. Можно, конечно, предположить, что как раз при выполнения этих запросов, Ubuntu обнаруживает неполадки в сети и запускает свой таймер, который через некоторые промежутки времени проверяет состояние сети. На самом деле что происходит не знаю. После восстановления работоспособности сети, через некоторое время работоспособность программы так же восстанавливается.

Хотелось бы  добиться того, чтобы через lastError() ошибка обнаруживалась или exec() выдавал бы false, если запрос не осуществлен, а  не ввергал программу в литаргический сон.

Заранее благодарствую!


Название: Re: Ошибка не определяется.
Отправлено: Admin от Май 06, 2009, 13:42
У меня примерно похожая ситуация  - только база данных локальная. Я бы посоветовал следущее:

1) Использовать транзакции - тогда ваша программа не сможет повредить базу данных.
2) Каждый запрос выполнять в треде - не будет зависания интерфейса при долгих запросах. У самого щас раз в минуту запускается запрос по QTimer.


PS: про то, что БД отвалилась - должен сообщить драйвер. А вы откатить транзакцию. Это в идеале.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Май 07, 2009, 07:48
Спасибо за совет, но все осталось по старому. Попробовал использовать транзакции, в стабильном режиме программа работает не лучше и не хуже, а при отключении сети, перестает нормально функционировать, собственно, при начале транзакции QSqlDatabase::transaction(). Странно, что в Qt предусмотрен целый класс для работы с ошибками БД, только почему-то ошибки эти он корректно выдавать не хочет, независимо от того QSqlDriver::lastError(), QSqlDatabase::lastError() или QSqlQuery::lastError() вызываю. Видимо это я не понимаю всего предназначения QSqlError ??? Остальные функции (isOpenError() например) с помощью которых можно было бы обнаружить ошибку, молчат как партизаны :-X  Как, интересно, еще можно заставить Qt говорить :) Вы не знаете, как?


Название: Re: Ошибка не определяется.
Отправлено: break от Май 24, 2009, 01:34
Как вы имитируете долгое зависание программы - вы вынимаете шнурок?

Возможно запрос уже открыт и уже подвисает - может можно попробовать в отдельном запросе (который будет в параллельном потоке)
или открывать быстрый запрос - и для него проверять  lastErorr (типа select count(*) from SMALL_TABLE)

или открывать второе соединение с БД ( новый QSqlDatabase с именем "TEST_CONNECTION")- и уже если оно не прокатит - что-то пытаться сообщить пользователю (Типа "БД повисла - ждите когда отвиснет...")

может второй вариант заработает...


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 04, 2009, 08:32
Не прошло и пол года, опять вернулся к старой проблеме. Вероятность возникновения этой нештатной ситуации не слишком велика, но проработать ее для надежности всей системы все-таки требуется.
Как вы имитируете долгое зависание программы - вы вынимаете шнурок?
Я таким образом даже не имитирую, приостановка процесса самая натуральная происходит.

Решил, что проверять быстрым запросом каждый раз при обращении к БД (а они происходят достаточно часто) нецелесообразно, дабы не сказывалось на производительности и не загружать канал. Да и не уверен что при таком быстром запросе не произойдет тот самый останов процесса приложения. Соединение, как я уже говорил, формально присутствует, а вот по факту...

Пришел к выводу, что подходящим вариантом будет реализация еще одного потока, и попытка открытия в нем еще одного соединения QSqlDatabase. Но вот жадный я до ресурсов, хочу что бы запуск осуществлялся непосредственно при возникновении этой вот нештатной ситуации. Просмотрел все возможные события в документации по Qt, половину попробовал, момент остановки процесса зафиксировать не удалось. Может вы сталкивались с подобной ситуацией, знаете как выйти из ситуации.


Название: Re: Ошибка не определяется.
Отправлено: CroCIV от Август 04, 2009, 13:12
У QSqlDatabase есть замечательная функция bool isOpen () const полезно перед каждой транзакцией вызывать ее, если функция возвращает false, то запрос выполнять бессмысленно. Конечно абсолютно защитить от зависания она не может, т.к. сеть начать лагать может уже непосредственно при выполнении "большой" транзакции, но во-первых это маловероятно, во-вторых для этого можно немного усложнить алгоритм, например запуская транзакцию в паралельном процессе, пока пользователь дальше работает с программой, процесс пыжится пропихнуть запрос через лагосеть, а пользователю, пока текущий запрос не выполнен новые запросы либо запрещать либо ставить в очередь, если все мыслимые интервалы ожидания выполнения запроса уже прошли, кричать пользователю критической ошибкой. Можно, как вариант просто задать максимальное время выполнения запроса покороче, но иногда проще попинать администраторов чтоб сеть в порядок привели  ;D


Название: Re: Ошибка не определяется.
Отправлено: CroCIV от Август 04, 2009, 13:28
После восстановления работоспособности сети, через некоторое время работоспособность программы так же восстанавливается.
это похоже как если бы пакеты с запросом вставали в очередь сетевого интерфейса и ждали у моря погоды, т.к. сетевой интерфейс безнадежно висит ища в сети приемник. тогда тут луче в другом потоке ставить таймер с прерывателем процесса ожидания ответа от сервера, сервер сам откатит не подкоммиченные транзакции.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 04, 2009, 13:42
У QSqlDatabase есть замечательная функция bool isOpen () const полезно перед каждой транзакцией вызывать ее, если функция возвращает false, то запрос выполнять бессмысленно. Конечно абсолютно защитить от зависания она не может, т.к. сеть начать лагать может уже непосредственно при выполнении "большой" транзакции, но во-первых это маловероятно, во-вторых для этого можно немного усложнить алгоритм, например запуская транзакцию в паралельном процессе, пока пользователь дальше работает с программой, процесс пыжится пропихнуть запрос через лагосеть, а пользователю, пока текущий запрос не выполнен новые запросы либо запрещать либо ставить в очередь, если все мыслимые интервалы ожидания выполнения запроса уже прошли, кричать пользователю критической ошибкой. Можно, как вариант просто задать максимальное время выполнения запроса покороче, но иногда проще попинать администраторов чтоб сеть в порядок привели  ;D

1. Насчет isOpen() - извелся я с этими Qt'шными функциями еще до того как тему эту начал, поэтому и начал-то ее:) Ато сидел, кодил бы помаленьку дальше, изредка обращаясь к мануалу. Я же ведь весь мануал перерыл, прежде чем тему начать, все функции возможные перепробовал, о чем писал уже. Если б все так просто было...
2. Потоком я бы с удовольствием воспользовался, только как выявить, эту самую, нештатную ситуацию, когда запрос не выполняется по причине отсутствия сетевого соединения, что бы затем запускать поток и т.д. Ладно бы еще if(query.exec()) выдавал бы false, ато на этом exec'e процесс приостанавливается, но об этом я тоже уже писал.
А вот насчет проработки интервала ожидания, как-то в голову приходило, но так и не попробовал. Есть ли в Qt'шных sql-классах функции, которые позволяют регулировать этот параметр. Или проще самому реализовать с помощью QTimer и сигналов со слотами.


Название: Re: Ошибка не определяется.
Отправлено: CroCIV от Август 04, 2009, 14:43
На счет потока, то его надо сразу выделять, тут других вариантов нет
На счет уменьшения интервала времени смотри в void QSqlDatabase::setConnectOptions ( const QString & options = QString() ) но не все сервера умеют такую фичку


Название: Re: Ошибка не определяется.
Отправлено: break от Август 05, 2009, 00:06
Может проверять периодически(1 раз в мин) в парралельном потоке не соединение с БД а вообще доступность хоста на котором БД расположена - то есть тривиальный пинг выполнять и если не проходит считать что БД повисла?


Название: Re: Ошибка не определяется.
Отправлено: CroCIV от Август 05, 2009, 07:40
это будет мини ДДОСинг, а если к одному серверу будет в сто тыщ лилионав коннектов каждую минуту проверяющих жив ли сервер? ))


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 05, 2009, 08:55
Согласен с CroCIV, не смотря на то что он несколько утрирует.
Я в общем-то не возражаю против проверки соединения и других необходимых операций. Но вот задача как раз и состоит в том, чтобы не с какой-то периодичностью тестировать и проверять конкретные ресурсы (здесь БД, удаленный компьютер или еще что, по сути не важно), а только при необходимости, то есть при возникновении нештатной ситуации, в частности разрыва сетевого соединения. Ведь в этом случае должны высылаться какие-то события, или хотя бы при попытке выполнения запроса.


Название: Re: Ошибка не определяется.
Отправлено: break от Август 05, 2009, 11:39
Цитировать
Ведь в этом случае должны высылаться какие-то события, или хотя бы при попытке выполнения запроса.

Не все БД в принципе это умеют, почему не попробоваь реализовать такой механизм (событийное сообщение об отсутствие соединения) например через сокеты (если в них эта ф-сть присутствует - сообщение о разрыве соединения) или другой сетевой механизм в кот. есть поддержка событийного сообщения об отсутствие соединения на уровне ОС?


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 07, 2009, 10:19
почему не попробоваь реализовать такой механизм (событийное сообщение об отсутствие соединения) например через сокеты (если в них эта ф-сть присутствует - сообщение о разрыве соединения) или другой сетевой механизм в кот. есть поддержка событийного сообщения об отсутствие соединения на уровне ОС?

Собственно дошли до того, что использование Qt-шных SQL классов для определения такой банальной коллизии результата не дало (это умозаключение конечно действительно только при использовании MySQL). Дошел до того, что начал копаться в исходниках Qt и посмотрел непосредственно клиентскую библиотеку MySQL. Понял, что это не самый кратчайший путь решения задачи:) Получается, что бы определить состояние подключения остается два пути, реализовать свой собственный timeout или поработать с сокетами. Выбор пока остановился на втором. В Qt есть классы для управления оными (в частности QTcpSocket), достаточно насыщенные инструментарием. Вот только как-то работать с ними не получается. При первой же компиляции debugger выдал: "ошибка: QtNetwork: No such file or directory", - ссылаясь на включающую директиву "#include <QtNetwork>". Лично раньше с этими классами не работал. Может подскажите что не так.


Название: Re: Ошибка не определяется.
Отправлено: uriel от Август 07, 2009, 10:38
В файле проекта наверное забыли добавить строчку QT += network.


Название: Re: Ошибка не определяется.
Отправлено: CroCIV от Август 07, 2009, 12:14
и вообще, странно у тебя как-то Qt себя ведет, никогда подобных глюков ранее не замечал... какую ты configure ру строку параметров подсунул? м.б. стоит попробовать qt переснести?


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 10, 2009, 13:38
В файле проекта наверное забыли добавить строчку QT += network.
Модуль добавлен, а debugger выдает тоже самое. В чем дело не могу понять.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 10, 2009, 13:48
какую ты configure ру строку параметров подсунул? м.б. стоит попробовать qt переснести?
ставил на ubuntu из пакетов *.deb, скрипт configure не запускал. Думаю, если переснесу - ничего не изменится. Может еще какие варианты есть?


Название: Re: Ошибка не определяется.
Отправлено: uriel от Август 10, 2009, 14:29
А в Ubuntu там случаем не как в Debian'е? Вроде libqt4-core, libqt4-gui, libqt4-network, etc.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 10, 2009, 14:38
А в Ubuntu там случаем не как в Debian'е? Вроде libqt4-core, libqt4-gui, libqt4-network, etc.
Да пакеты похожи. Собственно ubuntu на основе debiana'а и построена. Не удивлюсь, если пакеты одни и теже. Но утверждать не буду, не вникал.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 10, 2009, 15:24
В файле проекта наверное забыли добавить строчку QT += network.
Модуль добавлен, а debugger выдает тоже самое. В чем дело не могу понять.
Не совсем, конечно, то же самое. Теперь это: "mainwindow.h:196: предупреждение: ISO C++ запрещает декларации ‘QTcpSocket’ без типа" - пишет во время сборки.


Название: Re: Ошибка не определяется.
Отправлено: registrationfedser87 от Август 11, 2009, 06:31
добавь
Код
C++ (Qt)
#include <QTcpSocket>


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 11, 2009, 07:22
добавь
Код
C++ (Qt)
#include <QTcpSocket>
Обижаете. Эта директива изначально включена.


Название: Re: Ошибка не определяется.
Отправлено: Tritiy от Август 11, 2009, 13:34
Разобрался с QTcpSocket, нашел свои недочеты. Но на конечный результат это не повлияло. Очевидно, что соединение посредством QSqlDatabase, не что иное как сокетное соединение по 3306 порту. Только вот наследование QTcpSocket и QSqlDatabase осуществляется от разных родителей. Sql классы Qt - это интерфейс, обеспечивающий доступ к разным клиентским SQL библиотекам, в которых, как раз, и реализовано это сокетное соединение с базой данных. И вот тут, как раз, возникает вопрос: существует ли возможность хотя бы получать информацию, о этом вот сокетном соединении. Или целесообразней попробовать создать его аналог в другом потоке посредством класса QTcpSocket, и отслеживать его состояние, если я, конечно, все правильно понимаю.


Название: Re: Ошибка не определяется.
Отправлено: ритт от Август 19, 2009, 22:50
в случае с мускулем всё немного сложнее, т.к. мускуль может работать и с вовсе отключённым tcp/ip - через именованные сокеты...но не суть...
а есть возможность добавить пару строк в драйвер qmysql или форкнуть его его и использовать свой?