TSQLQuery + MySQL
Модератор: Модераторы
Запускается приложение. Во время старта соединяюсь с БД MySQL. Работаем. Тут БАЦ! - оборвалась связь с БД (упала сеть). Отправляется очередной запрос SQLQuery.Open; и приложение повисает............... Поднимаем сеть, и приложение продолжает работать как-будто ничего не происходило. Вопрос: как отследить, что запрос делать не нужно, по причине отсутствия связи с БД (упала сеть, или глюканул сервак с MySQL)?
Проверять ответ сервера перед отправкой(например содержимое ID 555) и проверять после отправки(например получать ID новой записи).
Даже если есть стандартная функция проверки - она делает примерно тоже самое. (PS: спасибо за дебагер
)
Разве open не возвращает true?
ещё try except - это сохранит быстродействие
.
Даже если есть стандартная функция проверки - она делает примерно тоже самое. (PS: спасибо за дебагер
Разве open не возвращает true?
ещё try except - это сохранит быстродействие
.
Дело в том, что зависание происходит внутри SQLQuery.Open. И приходится долго ждать: либо сообщения об ошибке, либо пока не возобновится связь (поднимется сеть). Мне бы: либо где-то сократить таймаут ожидания, либо перед SQLQuery.Open как-то узнать доступность сервера...
Мой код:
Мой код:
Код: Выделить всё
function UFMySQLConnector.DoAnySQL(SQL: TStringList): integer;
var
i, fi, fc: integer;
ss: string;
begin
if SQL = nil
then begin
Result := -1;
exit;
end;
fSQLQuery.sql.Text := SQL.Text;
{$ifdef _login}
Log.LogStatus(SQL.Text, 'DoAnySQL');
{$endif}
try
fSQLQuery.Open; // Выполняем запрос на сервер
except // Если запрос неудался
fMySQLConnection.Close(true); // Форсируем закрытие соединения
try
fMySQLConnection.Open; // Открываем новое соединение
// Если соединение удалось, то повторно отправляем запрос
if fMySQLConnection.Connected then fSQLQuery.Open;
except
Result := -2; // Иначе сообщаем об обрыве связи с сервером
Exit;
end;
end;
fSQLQuery.Last;
Result := fSQLQuery.RecordCount;
fSQLQuery.First;
if Result > 0
then begin
SQL.Clear;
fc := pred(fSQLQuery.FieldCount);
for i := 1 to Result
do begin
ss := '';
for fi := 0 to fc do ss += (fSQLQuery.Fields[fi].AsString + FSeparator);
Delete(ss, Length(ss), 1);
SQL.Append(ss);
fSQLQuery.Next;
end;
end;
fSQLQuery.Close;
fSQLTransaction.Commit;
end; может так?
if fMySQLConnection.Active then ...
или можно сразу проверять до запроса fMySQLConnection.Connected?
.
if fMySQLConnection.Active then ...
или можно сразу проверять до запроса fMySQLConnection.Connected?
.
vitaly_l писал(а):if fMySQLConnection.Active then ...
Объявлено как:
Код: Выделить всё
fMySQLConnection: {$ifdef unix}TMySQL56Connection{$endif}{$ifdef windows}TMySQL55Connection{$endif};Нет там такого свойства... А Вы какой класс имели ввиду?
- я по аналогии попробовал.VirtUX писал(а):Нет там такого свойства...
Тогда запускайте fMySQLConnection.Connected, перед обращением к серверу.
Сразу разрывайте соединение и тут же восстанавливайте при каждом обращении к серверу и будет Вам счастье.
Вот готовый кусок из Вашего кода:
Код: Выделить всё
fMySQLConnection.Close(true); // Форсируем закрытие соединения
try
fMySQLConnection.Open; // Открываем новое соединение
if fMySQLConnection.Connected then fSQLQuery.Open;
except
Result := -2; // Иначе сообщаем об обрыве связи с сервером
Exit;
end;
Ясно. Спасибо! Попробую...
Очень плохо что ту Вас долго открыто соединение с сервером, в PHP как правило установлен лимит по времени 30 секунд, а потом автоматическое отключение. У MySQL - это очевидно тоже должно быть, т.к. иначе 555 человек смогут повесить MySQL сервер. Поэтому Вас и разъединяет постоянно, т.к. там лимит по времени соединения. Поэтому, лучше сразу после отправки данных разъединяйте соединение - это более корректно по отношению к удалённому серверу.
- pi1
- новенький
- Сообщения: 59
- Зарегистрирован: 19.04.2012 18:11:24
- Откуда: г.Зеленокумск
- Контактная информация:
Не пробовал с MySQL, но с FireBird мне для вывода в DBGrid всех выбранных записей приходилось перемещать курсор датасета на последнюю запись.
То есть fSQLQuery.Open->fSQLQuery.Last->fSQLQuery.First.
То есть fSQLQuery.Open->fSQLQuery.Last->fSQLQuery.First.
- GAMER
- энтузиаст
- Сообщения: 627
- Зарегистрирован: 06.08.2008 13:41:07
- Откуда: Ужгород-Днепр, Украина
- Контактная информация:
Код: Выделить всё
Reconnect:= True;
Protocol:= {$IFDEF FPC} Integer(MYSQL_PROTOCOL_TCP) {$ELSE} 1 {$ENDIF};{Timeout only applies for TCP connections}
if (MySQL_Options(MySock, MYSQL_OPT_CONNECT_TIMEOUT, @ATimeOut) <> 0) or
(MySQL_Options(MySock, MYSQL_OPT_READ_TIMEOUT, @ATimeOut) <> 0) or
(MySQL_Options(MySock, MYSQL_OPT_WRITE_TIMEOUT, @ATimeOut) <> 0) or
(MySQL_Options(MySock, MYSQL_OPT_RECONNECT, @Reconnect) <> 0) or
(MySQL_Options(MySock, MYSQL_OPT_PROTOCOL, @Protocol) <> 0) then
MySQLErrMsg:='Unknown option specified.';
if MySQL_Real_Connect(MySock, Host, MyUser, Password,
nil {db}, MyPort{3306}, nil {unix socket}, {CLIENT_REMEMBER_OPTIONS}clientflag)=nil then Это часть кода которая подключается к Мускулю. Можно поиграться с параметрами. То есть задать время реакции на пропадание коннекта, нужен ли реконект и т.д.
GAMER писал(а):нужен ли реконект и т.д.
MySQL всегда разрывает connect т.к. многие забывают это сделать и сервер иначе повиснет при users > 555.
Увеличить время connect имеет смысл только в случае, если нужно в течении минуты многократно слать туда-сюда какие-то данные.
Во всех остальных случаях - лучше делать реконект, т.к. отправка 1000 несложных записей, даже с реконектом, занимает меньше секунды.
А тут нужно одну отправлять в час или в минуту(если я правильно понял)... и зачем держать сервер в течении часа в напряжении?
- GAMER
- энтузиаст
- Сообщения: 627
- Зарегистрирован: 06.08.2008 13:41:07
- Откуда: Ужгород-Днепр, Украина
- Контактная информация:
Не всегда. Вернее есть какой-то таймаут, но я не знаю где он задается. По крайней мере, мой софт иногда вылетает при разрыве коннекта, а соединение еще долго висит в процесах (явно больше минуты). С другой стороны, если есть активная сессия и при этом tcp/ip сессия кратковременно оборвалася, то мускуль создает коннект с предыдущими параметрами.
Я говорил по аналогии с PHP, там скрипт по умолчанию обязательно разрывается в через 30 секунд и уничтожает MySQL сессию. То что у Вас висит процесс, это не значит что этот же процесс должен висеть и на сервере. И на сервере должны быть специальные подпрограммы, которые подчищают оборванные сессии, т.к. если сессий будет равнозначно количеству пользователей в день, то сервер сдохнет через несколько минут после перезагрузки. Попробуйте запустить у себя 1000-1000000 сессий и Ваша машина обязательно начнёт тормозить. На сервере всё тоже самое.
У меня бывает и по 100000 подряд обращений к серверу. Если сеть физически не пропадает, то все работает отлично (одновременно подключеных клиентов < 10). Но вот если связь обрывается (по разным причинам), то клиент при отправке запроса (SQLQuery.Open) повисает пока не произойдет: либо связь восстановлена (и тогда запрос отрабатывается, как-будто обрыва и не было), либо сообщение об ошибке. Меня не устраивает здесь только одно - длительная пауза зависания.
Я всегда считал, что правильнее поддерживать коннект с сервером как можно дольше. Но теперь мне понятно, что лучше обрывать его после каждого запроса.
Я всегда считал, что правильнее поддерживать коннект с сервером как можно дольше. Но теперь мне понятно, что лучше обрывать его после каждого запроса.
- GAMER
- энтузиаст
- Сообщения: 627
- Зарегистрирован: 06.08.2008 13:41:07
- Откуда: Ужгород-Днепр, Украина
- Контактная информация:
Не считаю хорошей идеей строить логику работы для работы с мусей так, чтобы какждый запрос проходил всю цепочку: коннект, авторизация, выполнение, закрыть.
Например, при такой логике нет возможности использовать временный таблицы. В каждой задаче должен быть свой подход.
Лично я оспользую логику: один экземплячр программы - одно соединение. При превышении таймаута - ошибка. Но в моем случае активных сессий мало. Для веб-сервиса такой прием не подходит.
Например, при такой логике нет возможности использовать временный таблицы. В каждой задаче должен быть свой подход.
Лично я оспользую логику: один экземплячр программы - одно соединение. При превышении таймаута - ошибка. Но в моем случае активных сессий мало. Для веб-сервиса такой прием не подходит.
