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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Ошибка не определяется.  (Прочитано 14760 раз)
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, если запрос не осуществлен, а  не ввергал программу в литаргический сон.

Заранее благодарствую!
Записан
Admin
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1988



Просмотр профиля
« Ответ #1 : Май 06, 2009, 13:42 »

У меня примерно похожая ситуация  - только база данных локальная. Я бы посоветовал следущее:

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


PS: про то, что БД отвалилась - должен сообщить драйвер. А вы откатить транзакцию. Это в идеале.
Записан
Tritiy
Гость
« Ответ #2 : Май 07, 2009, 07:48 »

Спасибо за совет, но все осталось по старому. Попробовал использовать транзакции, в стабильном режиме программа работает не лучше и не хуже, а при отключении сети, перестает нормально функционировать, собственно, при начале транзакции QSqlDatabase::transaction(). Странно, что в Qt предусмотрен целый класс для работы с ошибками БД, только почему-то ошибки эти он корректно выдавать не хочет, независимо от того QSqlDriver::lastError(), QSqlDatabase::lastError() или QSqlQuery::lastError() вызываю. Видимо это я не понимаю всего предназначения QSqlError Непонимающий Остальные функции (isOpenError() например) с помощью которых можно было бы обнаружить ошибку, молчат как партизаны Рот на замке  Как, интересно, еще можно заставить Qt говорить Улыбающийся Вы не знаете, как?
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #3 : Май 24, 2009, 01:34 »

Как вы имитируете долгое зависание программы - вы вынимаете шнурок?

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

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

может второй вариант заработает...
Записан
Tritiy
Гость
« Ответ #4 : Август 04, 2009, 08:32 »

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

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

Пришел к выводу, что подходящим вариантом будет реализация еще одного потока, и попытка открытия в нем еще одного соединения QSqlDatabase. Но вот жадный я до ресурсов, хочу что бы запуск осуществлялся непосредственно при возникновении этой вот нештатной ситуации. Просмотрел все возможные события в документации по Qt, половину попробовал, момент остановки процесса зафиксировать не удалось. Может вы сталкивались с подобной ситуацией, знаете как выйти из ситуации.
Записан
CroCIV
Гость
« Ответ #5 : Август 04, 2009, 13:12 »

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

После восстановления работоспособности сети, через некоторое время работоспособность программы так же восстанавливается.
это похоже как если бы пакеты с запросом вставали в очередь сетевого интерфейса и ждали у моря погоды, т.к. сетевой интерфейс безнадежно висит ища в сети приемник. тогда тут луче в другом потоке ставить таймер с прерывателем процесса ожидания ответа от сервера, сервер сам откатит не подкоммиченные транзакции.
Записан
Tritiy
Гость
« Ответ #7 : Август 04, 2009, 13:42 »

У QSqlDatabase есть замечательная функция bool isOpen () const полезно перед каждой транзакцией вызывать ее, если функция возвращает false, то запрос выполнять бессмысленно. Конечно абсолютно защитить от зависания она не может, т.к. сеть начать лагать может уже непосредственно при выполнении "большой" транзакции, но во-первых это маловероятно, во-вторых для этого можно немного усложнить алгоритм, например запуская транзакцию в паралельном процессе, пока пользователь дальше работает с программой, процесс пыжится пропихнуть запрос через лагосеть, а пользователю, пока текущий запрос не выполнен новые запросы либо запрещать либо ставить в очередь, если все мыслимые интервалы ожидания выполнения запроса уже прошли, кричать пользователю критической ошибкой. Можно, как вариант просто задать максимальное время выполнения запроса покороче, но иногда проще попинать администраторов чтоб сеть в порядок привели  Смеющийся

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

На счет потока, то его надо сразу выделять, тут других вариантов нет
На счет уменьшения интервала времени смотри в void QSqlDatabase::setConnectOptions ( const QString & options = QString() ) но не все сервера умеют такую фичку
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #9 : Август 05, 2009, 00:06 »

Может проверять периодически(1 раз в мин) в парралельном потоке не соединение с БД а вообще доступность хоста на котором БД расположена - то есть тривиальный пинг выполнять и если не проходит считать что БД повисла?
Записан
CroCIV
Гость
« Ответ #10 : Август 05, 2009, 07:40 »

это будет мини ДДОСинг, а если к одному серверу будет в сто тыщ лилионав коннектов каждую минуту проверяющих жив ли сервер? ))
Записан
Tritiy
Гость
« Ответ #11 : Август 05, 2009, 08:55 »

Согласен с CroCIV, не смотря на то что он несколько утрирует.
Я в общем-то не возражаю против проверки соединения и других необходимых операций. Но вот задача как раз и состоит в том, чтобы не с какой-то периодичностью тестировать и проверять конкретные ресурсы (здесь БД, удаленный компьютер или еще что, по сути не важно), а только при необходимости, то есть при возникновении нештатной ситуации, в частности разрыва сетевого соединения. Ведь в этом случае должны высылаться какие-то события, или хотя бы при попытке выполнения запроса.
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #12 : Август 05, 2009, 11:39 »

Цитировать
Ведь в этом случае должны высылаться какие-то события, или хотя бы при попытке выполнения запроса.

Не все БД в принципе это умеют, почему не попробоваь реализовать такой механизм (событийное сообщение об отсутствие соединения) например через сокеты (если в них эта ф-сть присутствует - сообщение о разрыве соединения) или другой сетевой механизм в кот. есть поддержка событийного сообщения об отсутствие соединения на уровне ОС?
Записан
Tritiy
Гость
« Ответ #13 : Август 07, 2009, 10:19 »

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

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

В файле проекта наверное забыли добавить строчку QT += network.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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