Синхронизация DataSet/DBGrid на клиентах по сети

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

Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение wwswowsogon » 09.07.2020 22:27:58

Всем доброго времени суток!

Внезапно столкнулся с проблемой: при внесении/удалении данных в/из БД, внесенные изменения не отображаются на других сетевых клиентах, вплоть до перезагрузки программы на клиентской машине. Переоткрытие DataSet методами Refresh или Open/Close не помогает, увы.

Подскажите, плиз, в какую сторону копать.

Используется клиент-серверный Firebird 2.5, если что.
wwswowsogon
постоялец
 
Сообщения: 152
Зарегистрирован: 23.12.2008 20:41:37

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение Снег Север » 09.07.2020 22:44:38

Делать реконнект на клиенте? А вообще похоже на неверную настройку параметров транзакций.

ЗЫ. Я совершенно не знаток Firebird, но вот что нашел на хабре:
Для обычной работы (показ данных в гриде и т.п.) обычно используются режим изолированности READ COMMITED (Options.Isolation = xiReadCommited), т.к. он позволяет транзакции видеть чужие, committed изменения базы данных просто путём повторного выполнения запросов (перечитывания данных). Поскольку эта транзакция используется только для чтения, установим свойство Options.ReadOnly в значение True. Таким образом, наша транзакция будет иметь параметры read read_commited rec_version. Транзакция с такими параметрами в Firebird может быть открытой сколь угодно долгое время (дни, недели, месяцы), без блокирования других транзакций или влияния на накопление мусора в базе данных (потому что на самом деле, на сервере такая транзакция стартует как committed).
https://habr.com/ru/post/273549/
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3039
Зарегистрирован: 27.11.2007 16:14:47

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение zoltanleo » 10.07.2020 01:40:33

+1 к уровню изоляции. Еще есть механизм эвентов/событий, который позволяет делать рассылку уведомлений всем заинтересованным слушателям сети.

Вообще, про уровни изоляции и с чем их едят лучше читать здесь.
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 458
Зарегистрирован: 17.10.2013 10:55:01

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение haword » 10.07.2020 10:31:42

если уровень изоляции snapshot то так и будет до переконекта с обоих сторон. надо ставить readcommited и начинать усиленно использовать транзакции везде где нужно.
haword
постоялец
 
Сообщения: 301
Зарегистрирован: 02.03.2006 11:34:40

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение olegy123 » 10.07.2020 22:33:55

1) клиенты должны знать когда наступили изменения.
Они могут получить сообщение о том что данные изменились путем посылки POST_EVENT

Как правило POST_EVENT может сидеть в Тригерах на INSERT/UPDATE/DELETE или в PROCEDURE Interbase/Firebird

2) Клиент должен быть подписан на событие, тогда к нему прийдет данное сообщение.

3) Клиент получив событие волен обновить таблицу или данные.

Любое действие с БД обязано идти через Транзакцию, компоненты типа Zeos/Ado и другие - не требуют у клиента точного подхода, сами решают когда им открыть или закрыть транзакцию.
В IBX компонентах вы даже SELECT не сделаете без точного указания в каком режиме будет работать Транзакция.

Interbase/Firebird - это версионая база данных, любое действие прибавляет внутренний счетчик операций, отсюда когда открыли транзакцию, то вы множите не удивить следующих изменений, для этой транзакции они не известны, разумеется есть режимы которые позволяют читать новые данные и даже не завершенные другой транзакцией.

Теперь представте, что вы подключились к базе данных. Компонент у клиента открыл по умолчанию транзакцию, он делает работу в рамках этой транзакции, база данных не предоставляет ему новых данных вне этой транзакции, так как работает с устаревшими данными. Клиенту нужно выйти, закрыть свою транзакцию и заново зайти, с новой транзакцией.

Поэтому если вы пишите многосессионную систему, то пожалуйста изучите эту главу , и нужно очно знать как работают компоненты на стороне клиента.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение wwswowsogon » 10.07.2020 23:22:34

Спасибо всем за развёрнутые ответы!

Действительно, конструкция типа

Код: Выделить всё
SQLTransaction1.Active := false;
SQLTransaction1.Active := true;


частично спасает положение. Но, подозреваю, что этот приём может привести к проблемам, особенно если открыто несколько DataSet'ов.

про режимы изоляции и события ознакомился, по диагонали пока, спасибо. Я правильно понимаю, что эти механизмы реализуются больше через SQL-запросы, чем через методы и свойства объектов стандартных компонентов? :)
wwswowsogon
постоялец
 
Сообщения: 152
Зарегистрирован: 23.12.2008 20:41:37

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение zoltanleo » 11.07.2020 01:22:42

На самом деле компоненты доступа (кроме TIBTable, по-моему) используют все те же SQL-запросы, поэтому без них никуда.
Чтобы комфортно работать с данными и видеть все закоммиченные записи, достаточно задать параметры читающей транзакции (уровень изоляции readcommited):
read
nowait
record version

Для обновления содержимого датасета необязательно перезапускать транзакцию. Достаточно сделать Dataset.Refresh. Это делается либо через определенные интервалы времени программно, либо по кнопке пользователем, либо при получении post_event, о чем писалось выше.

Вообще, работа с транзакциями в компонентах IBX - это краеугольный камень работы с БД. Без их уверенного знания писать нормально работающие приложения вы не сможете. Поэтому настоятельно советую их разобрать подробно
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 458
Зарегистрирован: 17.10.2013 10:55:01

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение olegy123 » 11.07.2020 04:02:40

wwswowsogon писал(а): SQLTransaction1.Active := false;
SQLTransaction1.Active := true;


SQLTransaction - можно автоматически настроить путем галок. Когда ему начинать работать и когда завершать, в каком виде Commit/Rollback. И работает до SQLTransaction.Active:=false или уничтожении самого компонента SQLTransaction, завершается согласно установленному состоянию.


SQLTransaction.Active:=true => это есть SQLTransaction.StartTransaction; - при AutoOpen
SQLTransaction.Active:=false => SQLTransaction.Commit или SQLTransaction.Rollback - при AutoClose

а можно в ручную, советую
SQLTransaction.StartTransaction;
SQLQuery.Open
SQLQuery.Post;
SQLQuery.Close;
SQLQuery.ExecSQL;
...
...
...
SQLQuery.Open
SQLQuery.Post;
SQLQuery.Close;
SQLQuery.ExecSQL;

SQLTransaction.Commit; - все изменения подтверждаем; данные становятся видимые для всех.
SQLTransaction.Rollback; - все изменения отменяем; данные которая изменила состояние базы данных в этой транзакции откатываются до состояния SQLTransaction.StartTransaction;

попробуйте разместить две SQLTransaction1; SQLTransaction2; и соответственно SQLQuery1, SQLQuery2 подключите SQLTransaction1; SQLTransaction2.

и попробуйте посмотреть что будет происходить с базой данных для каждой SQLQuery1, SQLQuery2

Добавлено спустя 42 минуты 7 секунд:
wwswowsogon писал(а): правильно понимаю, что эти механизмы реализуются больше через SQL-запросы, чем через методы и свойства объектов стандартных компонентов?

А стандартные компоненты ничего не меняют при работе с базой данных. Они ведут себя как на автопилоте, если заложено в них открыть и не беспокоить программиста глубиным изучением правил работы с базой данных, то компоненты сами открывают транзакцию при первом обращении, и закрывают только после уничтожение компонента, или даже закрытия подключения к базы данных(в SQLConnection.transaction как бы намекает на это поведение), удобно при монопольной работе с базой данных.
Или же любое обращение порождает новую транзакцию. Этот режим позволяет увидить сразу все внесенные изменения. Но с ним невозможно работать в рамках комплексных работ:

необходимо внести 1000000 изменений за раз, нужно открыть и зафиксировать транзакцией 1000000 раз, что для базы данных это требует дополнительной нагрузки. Например в 1Ске, без явного указания запуска транзакций изменений и коммита - скорость работы в сотни раз уменьшается при массовых изменений, то что вы сможете за 1 минуту сделать - будете делать 2 часа.

синхронное работу связанных таблиц - необходимо комплексное изменение в разных таблицах разом. Без четкого применения транзакции, другие клиенты смогут увидеть одни данные раньше чем другие обновятся.

ну как пример - клиент меняет данные документа (контрагента, вносит шапку документа, заполняет реквизиты, добавляет позиции товар..) и клиент решает что не станет вносить изменения, жмет кнопку отменить. Транзакция делает Rollback - это достаточно отменить все изменения в рамках этой транзакции. Либо надо откатывается путем Delete.. этим очень сложно провести базу данных в то состояние до начало вбивая отмененного документа.

Если клиент отвалился - то база данных сама закроет все вносимые им изменения(они не подтверждены им).

При тонкой работе с StartTransaction/Commit/Rollback можно сделать комфортной работу для клиента, самим не придумывать "костыли" как вернуть первичное состояние, разрулить одновременную работу между многими клиентами.
С автопилотом, которые встроили разработчики компонента - он подходить скорее для монопольного режима.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение Снег Север » 11.07.2020 07:12:27

wwswowsogon, транзакции делаются сервером, ваши открытые или закрытые датасеты ни при чём. Ваша задача - правильно указать режим транзакции, которая привязана к вашему датасету. А режим указывается в свойствах компонента транзакций.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3039
Зарегистрирован: 27.11.2007 16:14:47

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение wwswowsogon » 19.07.2020 21:15:20

zoltanleo писал(а):На самом деле компоненты доступа (кроме TIBTable, по-моему) используют все те же SQL-запросы, поэтому без них никуда.


Да это понятно. ;)

zoltanleo писал(а):На самом деле компоненты доступа (кроме TIBTable, по-моему) используют все те же SQL-запросы, поэтому без них никуда.
Чтобы комфортно работать с данными и видеть все закоммиченные записи, достаточно задать параметры читающей транзакции (уровень изоляции readcommited):


А вот как это сделать средствами Lazarus, это вопрос. Там нет TDatabase, как в Delphi, видимо, в силу неактуальности BDE и иже с ним.

Снег Север писал(а):режим указывается в свойствах компонента транзакций.


Подозреваю, что в Lazarus это SQLTransaction.Action = (caNone, caCommit, caCommitRetaining, caRollback,
caRollbackRetaining);

Пробую менять эти значения, но пока особого эффекта не заметил. Скорее всего, я чего-то не понимаю.
wwswowsogon
постоялец
 
Сообщения: 152
Зарегистрирован: 23.12.2008 20:41:37

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение Снег Север » 19.07.2020 22:20:56

wwswowsogon
https://stackoverflow.com/questions/351 ... delphi-app

и используйте пакет IBX, у него больше возможностей для firebird
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3039
Зарегистрирован: 27.11.2007 16:14:47

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение zoltanleo » 19.07.2020 23:45:29

wwswowsogon писал(а):Подозреваю, что в Lazarus это SQLTransaction.Action = (caNone, caCommit, caCommitRetaining, caRollback,
caRollbackRetaining);

Пробую менять эти значения, но пока особого эффекта не заметил. Скорее всего, я чего-то не понимаю

"Чукча не читатель, чукча - писатель" ©

Код: Выделить всё
with SQLTransaction1 do
begin
  ...
  Params.Add('read');
  Params.Add('read_committed');
  Params.Add('rec_version');
  ...
end;


Настоятельно советую почитать выше приведенную ссылку про транзакции на ibase.ru или для FIBplus (хотя компоненты уже не поддерживаются, но написано очень понятно)

Не пользуйте встроенные компоненты Лазаря для работы с Firebird/IB - они сырые (я, например, так и не смог добиться загрузки библиотеки клиента, когда сервер был запущен в виде приложения на нестандартном порте).

Пользуйте хотя бы это IBX4Laz (если после его установки при загрузке среды компонент будет кричать, что не находит fbclient.dll/fbclient.so в системной папке и потому показываться не будет, подложите в корень установленного Лазаруса этот самый fbclient.dll/fbclient.so - для x32 Лазаря - от 32-битного FB, для x64 Лазаря - соответственно от 64-битного FB)
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 458
Зарегистрирован: 17.10.2013 10:55:01

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение wwswowsogon » 20.07.2020 17:07:09

Снег Север писал(а):wwswowsogonи используйте пакет IBX, у него больше возможностей для firebird


Спасибо, IBX скачал, мануал скачал, да, на вид там много полезного, буду изучать.
Увы, на начало работы над проектом знал только о существовании ZeOS, но решил делать без него.

zoltanleo писал(а):
Код: Выделить всё
with SQLTransaction1 do
begin
  ...
  Params.Add('read');
  Params.Add('read_committed');
  Params.Add('rec_version');
  ...
end;



Вах, вот оно как делается. А что такое rec_version?

zoltanleo писал(а):Не пользуйте встроенные компоненты Лазаря для работы с Firebird/IB - они сырые (я, например, так и не смог добиться загрузки библиотеки клиента, когда сервер был запущен в виде приложения на нестандартном порте).


Спасибо за подсказку.

zoltanleo писал(а):подложите в корень установленного Лазаруса этот самый fbclient.dll/fbclient.so - для x32 Лазаря - от 32-битного FB, для x64 Лазаря - соответственно от 64-битного FB)


Уже лежит, с самого начала. :)
wwswowsogon
постоялец
 
Сообщения: 152
Зарегистрирован: 23.12.2008 20:41:37

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение zoltanleo » 20.07.2020 17:16:35

wwswowsogon писал(а):Вах, вот оно как делается. А что такое rec_version?

Повторю в третий раз: читайте литературу, статья на 30 мин вдумчивого прочтения. Нет смысла пересказывать статью. Ссылки в предыдущих моих постах
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 458
Зарегистрирован: 17.10.2013 10:55:01

Re: Синхронизация DataSet/DBGrid на клиентах по сети

Сообщение Снег Север » 21.07.2020 07:11:59

wwswowsogon писал(а):А что такое rec_version?

Это RECORD_VERSION, один из параметров транзакции, подробности по нему читайте в документации FB.
http://www.ibase.ru/transactions/
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3039
Зарегистрирован: 27.11.2007 16:14:47

След.

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

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

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

Рейтинг@Mail.ru