TSQLQuery + MySQL

Модератор: Модераторы

Re: TSQLQuery + MySQL

Сообщение VirtUX » 29.12.2014 10:46:24

Запускается приложение. Во время старта соединяюсь с БД MySQL. Работаем. Тут БАЦ! - оборвалась связь с БД (упала сеть). Отправляется очередной запрос SQLQuery.Open; и приложение повисает............... Поднимаем сеть, и приложение продолжает работать как-будто ничего не происходило. Вопрос: как отследить, что запрос делать не нужно, по причине отсутствия связи с БД (упала сеть, или глюканул сервак с MySQL)?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 10.01.2015 13:03:02

Проверять ответ сервера перед отправкой(например содержимое ID 555) и проверять после отправки(например получать ID новой записи).
Даже если есть стандартная функция проверки - она делает примерно тоже самое. (PS: спасибо за дебагер :D )

Разве open не возвращает true?

ещё try except - это сохранит быстродействие


.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение VirtUX » 10.01.2015 20:29:26

Дело в том, что зависание происходит внутри 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;                   
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 10.01.2015 20:51:40

может так?
if fMySQLConnection.Active then ...
или можно сразу проверять до запроса fMySQLConnection.Connected?

.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение VirtUX » 10.01.2015 20:57:38

vitaly_l писал(а):if fMySQLConnection.Active then ...

Объявлено как:
Код: Выделить всё
fMySQLConnection: {$ifdef unix}TMySQL56Connection{$endif}{$ifdef windows}TMySQL55Connection{$endif};

Нет там такого свойства... А Вы какой класс имели ввиду?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 10.01.2015 21:07:35

VirtUX писал(а):Нет там такого свойства...
- я по аналогии попробовал.
Тогда запускайте fMySQLConnection.Connected, перед обращением к серверу.
Сразу разрывайте соединение и тут же восстанавливайте при каждом обращении к серверу и будет Вам счастье.
Вот готовый кусок из Вашего кода:
Код: Выделить всё
    fMySQLConnection.Close(true);  // Форсируем закрытие соединения
    try
      fMySQLConnection.Open;       // Открываем новое соединение
      if fMySQLConnection.Connected then fSQLQuery.Open;
    except
      Result := -2;         // Иначе сообщаем об обрыве связи с сервером
      Exit;
    end;
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение VirtUX » 10.01.2015 21:46:49

Ясно. Спасибо! Попробую...
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 10.01.2015 21:56:49

Очень плохо что ту Вас долго открыто соединение с сервером, в PHP как правило установлен лимит по времени 30 секунд, а потом автоматическое отключение. У MySQL - это очевидно тоже должно быть, т.к. иначе 555 человек смогут повесить MySQL сервер. Поэтому Вас и разъединяет постоянно, т.к. там лимит по времени соединения. Поэтому, лучше сразу после отправки данных разъединяйте соединение - это более корректно по отношению к удалённому серверу.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение pi1 » 11.01.2015 12:55:09

Не пробовал с MySQL, но с FireBird мне для вывода в DBGrid всех выбранных записей приходилось перемещать курсор датасета на последнюю запись.
То есть fSQLQuery.Open->fSQLQuery.Last->fSQLQuery.First.
Аватара пользователя
pi1
новенький
 
Сообщения: 59
Зарегистрирован: 19.04.2012 18:11:24
Откуда: г.Зеленокумск

Re: TSQLQuery + MySQL

Сообщение GAMER » 11.01.2015 17:42:03

Код: Выделить всё
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
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 11.01.2015 18:05:11

GAMER писал(а):нужен ли реконект и т.д.

MySQL всегда разрывает connect т.к. многие забывают это сделать и сервер иначе повиснет при users > 555.
Увеличить время connect имеет смысл только в случае, если нужно в течении минуты многократно слать туда-сюда какие-то данные.
Во всех остальных случаях - лучше делать реконект, т.к. отправка 1000 несложных записей, даже с реконектом, занимает меньше секунды.
А тут нужно одну отправлять в час или в минуту(если я правильно понял)... и зачем держать сервер в течении часа в напряжении?
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение GAMER » 11.01.2015 22:29:50

Не всегда. Вернее есть какой-то таймаут, но я не знаю где он задается. По крайней мере, мой софт иногда вылетает при разрыве коннекта, а соединение еще долго висит в процесах (явно больше минуты). С другой стороны, если есть активная сессия и при этом tcp/ip сессия кратковременно оборвалася, то мускуль создает коннект с предыдущими параметрами.
Аватара пользователя
GAMER
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина

Re: TSQLQuery + MySQL

Сообщение vitaly_l » 11.01.2015 22:58:24

Я говорил по аналогии с PHP, там скрипт по умолчанию обязательно разрывается в через 30 секунд и уничтожает MySQL сессию. То что у Вас висит процесс, это не значит что этот же процесс должен висеть и на сервере. И на сервере должны быть специальные подпрограммы, которые подчищают оборванные сессии, т.к. если сессий будет равнозначно количеству пользователей в день, то сервер сдохнет через несколько минут после перезагрузки. Попробуйте запустить у себя 1000-1000000 сессий и Ваша машина обязательно начнёт тормозить. На сервере всё тоже самое.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: TSQLQuery + MySQL

Сообщение VirtUX » 12.01.2015 10:30:43

У меня бывает и по 100000 подряд обращений к серверу. Если сеть физически не пропадает, то все работает отлично (одновременно подключеных клиентов < 10). Но вот если связь обрывается (по разным причинам), то клиент при отправке запроса (SQLQuery.Open) повисает пока не произойдет: либо связь восстановлена (и тогда запрос отрабатывается, как-будто обрыва и не было), либо сообщение об ошибке. Меня не устраивает здесь только одно - длительная пауза зависания.
Я всегда считал, что правильнее поддерживать коннект с сервером как можно дольше. Но теперь мне понятно, что лучше обрывать его после каждого запроса.
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: TSQLQuery + MySQL

Сообщение GAMER » 12.01.2015 12:21:25

Не считаю хорошей идеей строить логику работы для работы с мусей так, чтобы какждый запрос проходил всю цепочку: коннект, авторизация, выполнение, закрыть.
Например, при такой логике нет возможности использовать временный таблицы. В каждой задаче должен быть свой подход.
Лично я оспользую логику: один экземплячр программы - одно соединение. При превышении таймаута - ошибка. Но в моем случае активных сессий мало. Для веб-сервиса такой прием не подходит.
Аватара пользователя
GAMER
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина

Пред.След.

Вернуться в Базы данных

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru