Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 36 37 38 39 40 41 42 43 [44] 45   вперед  Ctrl
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
Здравствуйте!
Delphi 10.2, штатный FireDac, БД SQLite
Пишу Windows-службу, которая реализует TCP/IP-сервер, принимающий от клиентов данные, которые затем парсит, сохраняет в локальной БД, а отдельный поток периодически отправляет данные из этой БД POST-запросом PHP-скрипту для просмотра через web.
Может быть, надо было выбрать вместо SQLite какой-нить FB или MS SQL, но в обычных приложениях без многопоточной работы с БД проблем со связкой FireDac+SQLite не наблюдал, решил и в службе попробовать ее, разрулив доступ к БД из нескольких потоков критическими секциями (одновременных клиентов не так много и высокая скорость доступа не сильно критична).
Столкнулся с несколькими проблемами.
Перед подключением к БД (событие BeforeConnect) я пытаюсь сделать валидацию БД примерно так:
procedure Tdm.ConnectionBeforeConnect(Sender: TObject);
const
  dbname = 'name.db';
var
  s: string;
  f: Boolean;
begin
  try
    s := TPath.Combine(ExtractFilePath(ParamStr(0)), dbname);
    Connection.ConnectionString:='DriverID=SQLite;Database=' + s;
    // валидация БД
    SQLiteValidate.Database := s;
    if FileExists(s) then
    begin
      SQLog('Валидация БД...');
      cs.Enter;
      try
        f := SQLiteValidate.CheckOnly;
      finally
        cs.Leave;
      end;
      if (not f) then
      begin
        SQLog('Внимание! БД повреждена');
      end
      else
        SQLog('БД в порядке');
    end;}
  except
    on e: Exception do
    begin
      SQLog(e.Message, True);
    end;
  end;
end;

А после подключения к БД - проверяю существование таблиц и статичных данных справочников в некоторых из них, затем вызываю VACUUM:
procedure Tdm.ConnectionAfterConnect(Sender: TObject);
var
  s: string;
  f: Boolean;
begin
  try
    // создаем таблицы если не существуют
    sql :=
      'PRAGMA foreign_keys = off;' +
      'BEGIN TRANSACTION;' +
      // создаем таблицы
      'CREATE TABLE If Not Exists table1 (' +
      '    idx  INTEGER PRIMARY KEY ASC' +
      '                 UNIQUE' +
      '                 NOT NULL,' +
      '    name TEXT    NOT NULL' +
      ');' +
      ...
      // подтверждаем транзакцию
      'COMMIT TRANSACTION;' +
      'PRAGMA foreign_keys = on;'
      ;
    try
      cs.Enter;
      try
        Connection.ExecSQL(sql);
      finally
        cs.Leave;
      end;
    except
      on e: Exception do
      begin
        SQLog(e.Message, True);
      end;
    end;
    // заполняем таблицы значениями по умолчанию (если отсутствуют)
    FillDefaultValues;
    ClearTable(); // удаление старых записей
    Vacuum; // сжатие
  except
    on e: Exception do
    begin
      SQLog(e.Message, True);
      // raise Exception.Create(e.Message);
    end;
  end;
end;

procedure Tdm.Vacuum;
begin
  try
    ChkConnect;
    SQLog('Vacuum...');
    cs.Enter;
    try
      Connection.ExecSQL('VACUUM;');
    finally
      cs.Leave;
    end;
    SQLog(sOK);
  except
    on e: Exception do
    begin
      SQLog(e.Message, True);
    end;
  end;
end;

И в onDestroy удаляю записи старше определенного времени, после чего делаю Backup:
procedure Tdm.DataModuleDestroy(Sender: TObject);
var
  dt: TDateTime;
  dir: string;
begin
  try
    ClearTable;
    dt := Now;
    dir := TPath.Combine(ExtractFilePath(ParamStr(0)), 'backup');
    DbBackup(TPath.Combine(dir, Format('db_%.4u_%.2u_%.2u.bak', [YearOf(dt), MonthOf(dt), DayOf(dt)])));
  except
    on e: Exception do
    begin
      SQLog(e.Message, True);
    end;
  end;
  if Assigned(cs) then FreeAndNil(cs);
end;

procedure Tdm.DbBackup(const FileName: string);
var
  s: string;
begin
  try
    SQLog(Format('DbBackup (FileName = "%s")...', [FileName]));
    s := ExtractFilePath(FileName);
    if not DirectoryExists(s) then
    begin
      SQLog(Format('Создание папки: "%s"...', [s]));
      ForceDirectories(s);
      SQLog(sOK);
    end;
    SQLog('Создание резервной копии БД...');
    SQLiteBackup.Database := Connection.Params.Database;
    SQLiteBackup.DestDatabase := FileName;
    cs.Enter;
    try
      SQLiteBackup.Backup;
    finally
      cs.Leave;
    end;
    SQLog(sOK);
  except
    on e: Exception do
    begin
      SQLog(e.Message, True);
    end;
  end;
end;

Запускаю, работает, наполняю данными. Через несколько дней замечаю, что после ребута ПК служба не стартовала, в логах последняя запись "Валидация БД..." и все, похоже, что на валидации случился вылет. Комментирую код валидации, делаю ребут, теперь в логах все останавливается на "Vacuum...". Комментирую и вызов этого метода, служба успешно стартует после перезагрузок. Возвращаю оба метода, удаляю БД, чтобы служба создала ее самостоятельно, опять пару-тройку дней все работает и после очередного ребута те же грабли. ЧЯДНТ? Не так делаю валидацию, не так вызываю VACUUM (кстати, попробовал в Connection.Params.SQLiteAdvanced прописать auto_vacuum=1, но не заметил, чтобы файл БД после удаления записей уменьшился в размерах, а вот вызов аналогичного пункта меню в SQLiteStudio сразу сжал его раза в 3), не при том событии делаю бэкап, как-то повреждаю БД?
Еще при тесте интенсивной одновременной работы нескольких клиентов словил ситуацию, что полученные от них данные в течение одной минуты от всех отсутствуют, хотя после записи в БД ответ всеми клиентами был получен. Все остальное время все писалось в БД хорошо, поочередно обрабатывались по 1 пакету от каждого клиента. При записи данных из каждого потока дергаю процедуру дата-модуля, динамически создающую TFDQuery и формирующую запрос, ну и вдобавок qr.ExecSQL снова обернут критической секцией. Переключил LockingMode и Synchronous на Normal, попробую еще потестировать. Или в службе с многопоточным доступом к БД не стоит использовать SQLite и лучше сразу мигрировать на FB? Вообщем, буду признателен за критику и советы. :)
14 мар 19, 12:45    [21832387]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
З.Ы. Да, еще на случай багов FireDac попробовал скомпилить проект в 10.1, а также дома на самой крайней 10.3.1 CE, во всех случаях ситуация ровно такая же.
14 мар 19, 12:55    [21832399]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 25779
PalychXX
Вообщем, буду признателен за критику и советы. :)

Ребуты жесткие?
PalychXX
также дома на самой крайней

Я-бы сказал, что такое "крайняя"...
14 мар 19, 12:57    [21832403]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Игорь_UUS
Member

Откуда: г. Екатеринбург
Сообщений: 654
Michael Longneck
Если кто хочет таки использовать TVP в MSSQL с FireDac - пусть исправит в файле FireDac.Phys.ODBCWrapper в процедуре procedure TODBCVariable.UpdateFlags;

такой код

  else if SQLDataType = SQL_SS_TABLE then begin
    FScale := 0;
    FColumnSize := MaxInt; //было 1.
    FDataSize := 0;
  end


И всё заработает как надо



Мучительно больно использовать TVP в mssql. Багов много... все тянуться с XE7!

1.Нельзя использовать более одной переменной табличного типа в MSSQL. Вторая заполненная данными табличная переменная попросту приходит пустой в хранимку mssql.
2.Если в хранимой процедуре используется тип NVARCHAR(MAX), и за ней идёт табличная переменная, то последняя запись внесённая в табличную переменную не доходит до MSSQL. Т.е. чтоб работало корректно, нужно чтоб все переменные хранимки табличного типа шли первыми а за ними уже все переменные имеющие тип NVARCHAR(MAX).
3.С драйвером "неатив11" табличные переменные и вовсе не работают!!! (ПРОСТО ЖЕСТЬ!!!).

Чтоб обойти все эти баги приходиться придумывать всякие хитрости... табличные переменные сильно не доведены до ума.
14 мар 19, 13:27    [21832456]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Игорь_UUS
Member

Откуда: г. Екатеринбург
Сообщений: 654
Michael Longneck
Dmitry Arefiev
Что значит "победил" ?


Это значит нашёл второй баг, из-за которого второй и далее параметры TVP не заполнялись данными. Первый баг- тотЮ что я приводил ранее.


unit FireDAC.Phys.ODBCWrapper;

Первый
   else if SQLDataType = SQL_SS_TABLE then begin
    FScale := 0;
    FColumnSize := MaxInt; //было 1
    FDataSize := 0;
  end


Второй
function TODBCCommandStatement.PutLongParams: SQLReturn;
var
  pParamNum: SQLPointer;
  oPar: TODBCParameter;
  iCurNum: SQLSmallint;
  lFirst: Boolean;
  iIndex: Integer;
begin
  iCurNum := -1;
  oPar := nil;
  FFocusedParam := nil;
  iIndex := 0;
  lFirst := True;
  repeat
    pParamNum := nil;
    Result := Lib.SQLParamData(FHandle, pParamNum);
    if Result = SQL_NEED_DATA then begin
      // MSSQL: subsequent SQLParamData calls for TVP return pParamNum=nil
      if pParamNum <> nil then
      begin
        oPar := ParamList.FindByToken(pParamNum) as TODBCParameter;
        lFirst := True; //новый параметр, заначит надо DataReader сделать Reset  
      end;



Когда я озвучивал Dmitry Arefiev данные баги года три назад, услышал в ответ, что это недоработка со стороны майкрасофт...

теперь... заставить бы работать TVP ещё для последнего драйвера "неатив 11-го"
14 мар 19, 13:32    [21832471]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
wadman
Ребуты жесткие?

Раз в сутки в планировщике прописано задание "shutdown -r -f". Ну и обычная перезагрузка при тестах.
wadman
Я-бы сказал, что такое "крайняя"...

10.3.1 (Version 26.0.33219.4899).
14 мар 19, 13:34    [21832475]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Michael Longneck
Member

Откуда: Москва
Сообщений: 2298
Игорь_UUS
Мучительно больно использовать TVP в mssql. Багов много... все тянуться с XE7!

1.Нельзя использовать более одной переменной табличного типа в MSSQL. Вторая заполненная данными табличная переменная попросту приходит пустой в хранимку mssql.
2.Если в хранимой процедуре используется тип NVARCHAR(MAX), и за ней идёт табличная переменная, то последняя запись внесённая в табличную переменную не доходит до MSSQL. Т.е. чтоб работало корректно, нужно чтоб все переменные хранимки табличного типа шли первыми а за ними уже все переменные имеющие тип NVARCHAR(MAX).
3.С драйвером "неатив11" табличные переменные и вовсе не работают!!! (ПРОСТО ЖЕСТЬ!!!).

Чтоб обойти все эти баги приходиться придумывать всякие хитрости... табличные переменные сильно не доведены до ума.


На текущий момент я практически всё довёл до ума, и никаких проблем не ощущаю, 2 пункт не проверял. Исправлений пришлось сделать побольше чем я раньше описал. Native Client 11 сильно не новый драйвер.
14 мар 19, 14:32    [21832627]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Игорь_UUS
Member

Откуда: г. Екатеринбург
Сообщений: 654
Michael Longneck
Игорь_UUS
Мучительно больно использовать TVP в mssql. Багов много... все тянуться с XE7!

1.Нельзя использовать более одной переменной табличного типа в MSSQL. Вторая заполненная данными табличная переменная попросту приходит пустой в хранимку mssql.
2.Если в хранимой процедуре используется тип NVARCHAR(MAX), и за ней идёт табличная переменная, то последняя запись внесённая в табличную переменную не доходит до MSSQL. Т.е. чтоб работало корректно, нужно чтоб все переменные хранимки табличного типа шли первыми а за ними уже все переменные имеющие тип NVARCHAR(MAX).
3.С драйвером "неатив11" табличные переменные и вовсе не работают!!! (ПРОСТО ЖЕСТЬ!!!).

Чтоб обойти все эти баги приходиться придумывать всякие хитрости... табличные переменные сильно не доведены до ума.


На текущий момент я практически всё довёл до ума, и никаких проблем не ощущаю, 2 пункт не проверял. Исправлений пришлось сделать побольше чем я раньше описал. Native Client 11 сильно не новый драйвер.


Что касается Native Client 11, новый/не новый... он идёт в комплекте установки mssql2016-2017... других просто не пробовал, и тут другой вопрос, идёт ли поддержка FD более нового чем 11-й драйвер?!
14 мар 19, 15:07    [21832682]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Michael Longneck
Member

Откуда: Москва
Сообщений: 2298
Не знаю. "Поддержка" это просто константы в файле. Дописал и у меня на XE7 поддерживается до ODBC Driver 17 включительно.
14 мар 19, 15:15    [21832696]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
Хочу для сравнения попробовать то же самое с FB, пока время позволяет. Правильно я понимаю, что если установить сервер FB, то FireDac из Delphi редакции Pro без купленного Client/Server пака не даст подключиться даже к серверу на 127.0.0.1 и в этом случае мне нужно работать через IBX или другие альтернативные компоненты? А то в табличке с редакциями Delphi фраза "Создание приложений для баз данных с локальным и встроенным подключением" вызывает вопрос, чем локальное подключение отличается от встроенного, является ли оно подключением к серверу на локалхосте или это что-то другое.
15 мар 19, 09:43    [21833311]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Vlad F
Member

Откуда:
Сообщений: 875
PalychXX,

Говорят, что всеже даст, просто это будет нарушением соглашения.
Но если это не смущает, то флаг те в руки проверить/доложить.
15 мар 19, 10:18    [21833362]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
Vlad F
Говорят, что всеже даст, просто это будет нарушением соглашения.
Но если это не смущает, то флаг те в руки проверить/доложить.

А в случае с IBX не будет нарушением?
Про ADO в свое время сотрудник Эмбаркадеры отвечал, что можно по сети.
З.Ы. Наконец, словил на тестах в логах ошибку:
DBLOG
[FireDAC][Phys][SQLite] ERROR: database disk image is malformed

Мда, с SQLite в данном случае, видимо, лучше мигрировать на клиент-серверную БД...
15 мар 19, 10:24    [21833376]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Vlad F
Member

Откуда:
Сообщений: 875
PalychXX,

А в случае с IBX, говорят, что не будет.)) Да, и реализовывай в своих экспериментах сразу по отдельному
подключению на каждый поток, что бы не дискредитировать попусту используемые библиотеки.
15 мар 19, 10:37    [21833386]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
Vlad F
А в случае с IBX, говорят, что не будет.)) Да, и реализовывай в своих экспериментах сразу по отдельному
подключению на каждый поток, что бы не дискредитировать попусту используемые библиотеки.

Чудесно, тогда попробую FB + IBX, чтобы наверняка. Про отдельные подключения весьма дельный совет, спасибо! Так и сделаю.
15 мар 19, 16:30    [21834048]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10967
PalychXX
тогда попробую FB + IBX


http://www.loginovprojects.ru/index.php?page=ibxfbutils
15 мар 19, 18:23    [21834195]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Vlad F
Member

Откуда:
Сообщений: 875
PalychXX
Чудесно, тогда попробую FB + IBX, чтобы наверняка. Про отдельные подключения весьма дельный совет, спасибо! Так и сделаю.

Мы ждем от тебя заключения.))
15 мар 19, 22:11    [21834367]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
PalychXX
Member

Откуда:
Сообщений: 143
Arioch
http://www.loginovprojects.ru/index.php?page=ibxfbutils

Спасибо, пул подключений самое то, что нужно для этой задачи!
Vlad F
Мы ждем от тебя заключения.))

Ну чтож.)))
Наконец дошли руки сварганить несколько таблиц и пару хранимок в FB. Попробовал модули для IBX от Дмитрия Логинова, при первом знакомстве все понравилось. Без лишнего геммора в потоках получаю подключение из пула, выполняю запросы/хранимки и возвращаю подключение в пул, красота. По крайней мере на 500 одновременных потоках в клиент-серверной версии все писалось в базу на ура. Допишу модуль и попробую в боевом проекте.
А что, IBX так до сих пор и не поддерживает x64 компиляцию? И у FireDac из коробки нет пула подключений (судя по докам на Эмбаркадере, с ним как раз нужно для каждого потока свой Connection создавать)? В данном проекте это без разницы, но в планах еще клиент-серверные приложухи, где билды под x32 и x64 очень желательны. Если понадобится FireDac с сеткой, к старой лицензии все еще можно докупить ДБ-аддон за 400 баксов или для сетевого FD чтобы ничгео ен нарушать катит только новая лицуха Enterprise/Architect?
20 мар 19, 16:48    [21838725]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10967
PalychXX,

это не мне, это вот этому вот - https://www.sql.ru/forum/memberinfo.aspx?mid=109526
20 мар 19, 17:46    [21838793]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
kenesg12
Member

Откуда: Казахстан
Сообщений: 23
Здравствуйте знатоки!
Перешел на Firebird 3.0, и тут заметил что при выходе программа зависает и дальше ее вырубать только через диспетчер. Также Firebird необходимо перезапускать, т.к. уже не подключается к базе.

При исследовании обнаружил, что зависание происходит в момент деактивации FDEventAlerter. Как только передаю значение false, все уходит в зависон.

Подскажите как победить такую ситуацию, это баг или что настроить нужно? В 2.5 все работало как часы.
17 апр 19, 20:49    [21865574]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
kenesg12
Member

Откуда: Казахстан
Сообщений: 23
kenesg12,

Проблему решил.
У меня динамически создаются обьекты и каждый объект добавляет ивент в список TFDEventsAlerter, так вот заметил, что если добавлять винтов больше 20-25, то данный компонент не работает корректно и при разрыве соединения зависает. Но если меньше то норм.
В общем если ивентов становиться больше 10 то создаю динамически новый алертер и т.д.
Работает стабильно. Вот такая особенность в FB3.0
20 апр 19, 09:53    [21867694]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
cptngrb
Member

Откуда:
Сообщений: 369
В FireDac есть пул соединений. У пула есть два параметра
POOL_CleanupTimeout
The timeout (msecs) when FireDAC will remove connections unused more than POOL_ExpireTimeout time. Default value is 30000 msecs (30 secs). 
Время, через которое пул удаляет ненужное соединение.


POOL_ExpireTimeout
The time (msecs) after which the inactive connection may be deleted from the pool and destroyed. Default value is 90000 msecs (90 secs). 
Время, через которое пул может удалить неактивное соединение.


А что такое ненужное и неактивное в нотации Oracle?
7 июн 19, 16:51    [21904729]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1558
Неважно какая нотация..
Пул приложений у FireDAC свой собственный велосипед и абстрагирован от СУБД. Он не использует пулы от ODBC и т.п.
7 июн 19, 20:20    [21904924]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1558
Из-за этого кстати могут возникать проблемы при переиспользовании.
Например пул ODBC под MSSQL при каждом переиспользовании соединения вызывает sp_reset_connection, которая чистит весь контекст соединения от мусора который мог остаться при предыдущем вызове. Чего, как я понял FD не делает. И если вы забыли удалить временную таблицу, то при следующем переиспользовании соединения в другом месте может выйти это боком.
7 июн 19, 20:23    [21904926]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9746
Нужен тикет и тогда будет делать.
7 июн 19, 20:25    [21904927]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
cptngrb
Member

Откуда:
Сообщений: 369
X-Cite, хорошо, перефразирую

А что такое ненужное и неактивное соединение в нотации FireDac?
10 июн 19, 08:35    [21905651]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 36 37 38 39 40 41 42 43 [44] 45   вперед  Ctrl
Все форумы / Delphi Ответить