Не обновляется НД после Insert

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Не обновляется НД после Insert

Сообщение bender » 11 июл 2005, 16:37

Может ламерский вопрос, но уже который час не могу обновить набор данных, а именно:

1) Использую IBX
2) На форме IBQuery1, IBQuery2, одна транзакция Trn
3) IBQuery1, связан с DBGrid и выполняет select из таблицы Devices
4) IBQuery2 по нажатию кнопки выполняет:
IBQuery1->SQL->Add("insert into devices (MODEL_ID) values (1)");
IBQuery1->ExecSQL();
Trn->CommitRetaining();
IBQuery1->Refresh();

Все зашибись выполняется, но набор данных не обновляется в DBGrid. Делать IBQuery1->Close() IBQuery1->Open() как-то некрасиво, где я ошибаюсь?

McArty
Сообщения: 56
Зарегистрирован: 14 янв 2005, 09:31

Re: Не обновляется НД после Insert

Сообщение McArty » 11 июл 2005, 16:48

bender писал(а):Может ламерский вопрос, но уже который час не могу обновить набор данных, а именно:

1) Использую IBX
2) На форме IBQuery1, IBQuery2, одна транзакция Trn
3) IBQuery1, связан с DBGrid и выполняет select из таблицы Devices
4) IBQuery2 по нажатию кнопки выполняет:
IBQuery1->SQL->Add("insert into devices (MODEL_ID) values (1)");
IBQuery1->ExecSQL();
Trn->CommitRetaining();
IBQuery1->Refresh();

Все зашибись выполняется, но набор данных не обновляется в DBGrid. Делать IBQuery1->Close() IBQuery1->Open() как-то некрасиво, где я ошибаюсь?
Через Refresh не пройдёт,
хочешь узнать почему: создай IBDATASET в SELECTSQL укажи
то,что тебе надо и сгенери запросы.
см. REFRESH SQL.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Re: Не обновляется НД после Insert

Сообщение bender » 11 июл 2005, 17:05

McArty писал(а):Через Refresh не пройдёт,
хочешь узнать почему: создай IBDATASET в SELECTSQL укажи
то,что тебе надо и сгенери запросы.
см. REFRESH SQL.
То есть это получится связка IBQuery+IBUpdateSQL, а если я хочу в отдельном потоке, при помощи своего IBQuery или IBSQL (в поток передается указатель на IBDatabase, созданный в основном потоке)

Раньше юзал IBO, там Refresh работал, и еще там был Refresh() для транзакции.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 11:11

Мужики, я голову сломал, перечитал несколько факов по транзакциям и IBX компонентам, объясните неразумному почему так происходит:

Переделал приложение, так, что теперь есть две транзакции Trn1 и Trn2. Trn1 имеет параметры: read read_committed rec_version, Trn2 параметры: read_committed rec_version wait. С первой транзакцией связан компонент IBQuery1 с запросом "select * from DEVICES" (Обновлять данные в этой транзакции мне не нужно, только читать). Со второй транзакцией связан компонент IBQuery2 со следующим кодом "insert into devices (MODEL_ID) values (1)".
Работает все это следующим образом: при запуске приложения открывается IBQuery1, при нажатии кнопки "Add" стартует (принудительно) транзакция Trn2, вызывается метод IBQuery2->ExecSQL(), делается Trn2->Commit(), делается IBQuery1->Refresh(). И ничего не обновляется, т.е. набор данных возвращаемый IBQuery1 остается прежним, нафига тогда нужен этот Refresh()

Помогите пожалуйста, что не так. Мне обязательно нужно, чтобы один IBQuery1 читал, а другой IBQuery2 писал, но при этом IBQuery1 должен видеть изменения IBQuery2 после IBQuery2->Commit()

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 июл 2005, 12:43

Ну нету у TIBQuery проперти RefreshSQL, нее-ту. И искусственным интеллектом для построения оного оно не обладает. Метод Refresh остался как затычка из-за происхождения оного компонента из племени TDataSet. TIBDataSet для чтения использовать и прописать ему RefreshSQL религия не позволяет или таковы требования ТЗ? Тогда переоткрывай TIBQuery и позиционируйся на запись через букмарки или локейтом.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 13:36

за faq ответишь? :) ibx.htm - это НЕ faq. Собственно, чего ты привязался к IBQuery?
То есть это получится связка IBQuery+IBUpdateSQL, а если я хочу в отдельном потоке, при помощи своего IBQuery или IBSQL (в поток передается указатель на IBDatabase, созданный в основном потоке)
какие потоки? цитирую ibx.htm:

При использовании IBDatabase (IBX) в многопоточных (multithreaded) приложениях, в том числе с web- или com-серверами, нужно соблюдать следующие правила:

1. соединение с БД не должно быть "локальным". То есть не c:\dir\data.gdb, а сетевым - localhost:c:\dir\data.gdb.
2. в одном thread допускается работа только с одним IBDatabase. Причем соединение с сервером должно осуществляться в главном thread, после чего допускается работа в контексте коннекта в отдельном thread.
Попытка осуществить работу с одним коннектом из разных threads может быть успешной, если использовать блокировки thread при обращении к этому коннекту (на мютексах, семафорах и т.п.). Но в результате работа всего приложения будет не многопоточной, то есть, превратится в псевдо-многопоточное по причине блокировок между threads при работе с одиним коннектом.
Последний раз редактировалось kdv 12 июл 2005, 17:35, всего редактировалось 1 раз.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 14:00

Читал я эти правила и их соблюдаю:
1) соединение через полное имя "сервер:путь"
2) в каждый дочерний поток я передаю указатель на один единственный IBDatabase, который создан и открыт в основном потоке приложения
3) синхронизация потоков будет осуществляться через TThread->Synchronize()

Но проблема пока не в этом, а в том что, цитата из статьи "Транзакции в InterBase": nowait read_committed rec_version
именно такой уровень изоляции будет видеть изменения, производимые другими транзакциями (но не раньше их завершения по commit), и минимально конфликтовать при обновлении или удалении данных.


Первая транзакция читает данные из таблицы, вторая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат) Помогает единственное, закрыть и открыть IBQuery, но как-то это не клеится с цитатой выше о видимости транзакций (Если оно так и должно работать, то я вопросов больше не имею)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 14:50

3) синхронизация потоков будет осуществляться через TThread->Synchronize()
ну, чем ты там потоки между собой синхронизируешь, это твое личное дело. Другое дело, что в одном коннекте 2 запроса в разных потоках выполнять нельзя.
которая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат)
читаешь не глазами, и не понимаешь вообще. Refresh обновляет ТЕКУЩУЮ ЗАПИСЬ ДАТАСЕТА!!! Чтобы увидеть данные, вставленные другими запросами, транзакциями, коннектами, приложениями - нужно ПЕРЕВЫПОЛНИТЬ ЗАПРОС (Close/Open).
Что тут непонятного?

опять цитирую ibx.htm
RefreshSQL - запрос для обновления текущей строки. Должен содержать условие отбора по первичному ключу или подобное, для выборки одной записи.
отсюда разве неясно?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 июл 2005, 14:52

bender писал(а):Читал я эти правила и их соблюдаю:
1) соединение через полное имя "сервер:путь"
2) в каждый дочерний поток я передаю указатель на один единственный IBDatabase, который создан и открыт в основном потоке приложения
3) синхронизация потоков будет осуществляться через TThread->Synchronize()
Если речь не об stateless application server with connections pool, то явно отдаёт проктологией. Но это не суть.
bender писал(а): Но проблема пока не в этом, а в том что, цитата из статьи "Транзакции в InterBase": nowait read_committed rec_version
именно такой уровень изоляции будет видеть изменения, производимые другими транзакциями (но не раньше их завершения по commit), и минимально конфликтовать при обновлении или удалении данных.
Таки это правда.
bender писал(а): Первая транзакция читает данные из таблицы, вторая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат) Помогает единственное, закрыть и открыть IBQuery, но как-то это не клеится с цитатой выше о видимости транзакций (Если оно так и должно работать, то я вопросов больше не имею)
Насчёт применения IBUpdateSQL не скажу, к проктологии не склонен, так что опыта нет, но если с IBDataSet то же самое - это значит, что либо неправильно написан RefreshSQL, либо коммитится не та транзакция, либо коммитится не вовремя либо ещё что-то не так в приложении.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 15:09

kdv писал(а): читаешь не глазами, и не понимаешь вообще. Refresh обновляет ТЕКУЩУЮ ЗАПИСЬ ДАТАСЕТА!!! Чтобы увидеть данные, вставленные другими запросами, транзакциями, коннектами, приложениями - нужно ПЕРЕВЫПОЛНИТЬ ЗАПРОС (Close/Open).
Что тут непонятного?
Теперь все стало на свои места, просто раньше пользовался IBO и там Refresh обновлял все записи, как если бы я сделал Close-Open.
Спасибо за ответ, остается непонятным один момент:
Допустим есть два приложения, оба открыли один и тот же набор данных, но каждое в своем коннекте (допустим эти приложения запущены на разных компьютерах). Через какое-то время первое приложение меняет набор данных и фиксирует его Commit'ом, для этого приложения не трудно опознать момент, когда необходимо переоткрыть набор данных, а как быть с приложением на другом компьютере?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 15:10

а как быть с приложением на другом компьютере?
а никак. в многопользовательской среде все вокруг меняют какие-нибудь данные. Не будешь же ты постоянно все рефрешить. А для оповещения о применении изменений существуют евенты.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 июл 2005, 15:27

kdv писал(а):
а как быть с приложением на другом компьютере?
а никак. в многопользовательской среде все вокруг меняют какие-нибудь данные. Не будешь же ты постоянно все рефрешить. А для оповещения о применении изменений существуют евенты.
Дима. Что ты наделал. Сейчас в полку гридорефрешителей по евентам прибудет. И dimitr кого-нибудь наконец застрелит. Я-то уже почти выработал иммунитет.

2 товарищ bender:

Про то, что ты ожидал от Refresh переотрытия запроса, я не подумал. Если функция этого резалтсета - отражать состояние какого-то _процесса_, то запрос переоткрывают по таймеру. Если же это список каких-то объектов для выбора и редактирования, и одновременное редактирование одной записи недопустимо и маловероятно, то в момент начала редактирования стартуют снапшот, в нём перечитывают именно эту запись, выполняют редактирование и попытку модификации в базе, коммитят снапшот, рефрешат строку в читающей транзакции. Тогда в случае одновременного редактирования гарантирован конфликт и его обрабатываем по вкусу. Если таковое событие очень вероятно, то на старте редактирования пытаются сразу установить пессимистическую блокировку записи, чтоб конфликт был до, а не после редактирования.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 15:31

Дима. Что ты наделал. Сейчас в полку гридорефрешителей по евентам прибудет. И dimitr кого-нибудь наконец застрелит. Я-то уже почти выработал иммунитет.
да я видел, к чему это идет. но.... например, не будешь же умалчивать что в сервере есть то или это. Вон, в треде про 40-гиговую базу - 3.5 миллиона транзакций в сутки. Как бы, никто не запрещает, я из-за ошибки разработчика видел и 6 миллионов в сутки...

Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 12 июл 2005, 15:49

а как быть с приложением на другом компьютере?
Кнопка "Обновить", когда пользователь захочет увидеть обновленный набор, жмет кнопку, коммит и переоткрытие запроса.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 15:52

Задача предполагается такая:

Есть БД приборов, данные по которым беруться из самих приборов, путем считывания через (допустим) Com-порт. Для работы с конкретным прибором создается свой поток, в который передается указатель на IBDatabase, далее в потоке в критической секции меняется (0->1) поле в таблице приборов, отвечающее за то, что прибор считывается каким-то потоком (и он соответственно становится недоступным другим потокам и пользователям). Происходит считывание данных, которые записываются в БД (опять же в критической секции) и посылается Event всем приложениям подписанным на этот Event, после чего происходит рефреш необходимых гридов. Так будет корректно? Кстати, а чем плох рефреш грида по событию?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 12 июл 2005, 16:00

Уууу, как всё запущено... Я ухожу, уже про организацию real-time систем на СУБД говорить сил нетути...

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 16:23

А где почитать?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 17:22

почитать тут, или в e.p.i эта тема не раз обсуждалась.

значит, должно быть так:
1. твоя софтина из ком-порта записывает данные В ФАЙЛ. Никаких баз данных.
2. другая софтина подчитывает данные ИЗ ФАЙЛА, и закидывает в базу. Дальше файл можно перемещать как обработанный или ошибочный в спец-каталоги, и архивировать.
3. никоим образом не рефрешить по евентам.

объясняю. 1+2 гарантируют что серверу БД не надо работать 24x7, и что при любом сбое (кроме сбоя пункта 1) данные не пропадут.
никакие тут потоки вообще не нужны и даже вредны.
пункт 3 - с какой частотой приходят данные, и кому с этой частотой их надо обновлять???

добавлю, что конечно, исходная идея смотрится "красиво" - потоки там, евенты, все дела. Но в реальной жизни это НЕ РАБОТАЕТ. То есть, потоки работают, евенты, но в такой комбинации и для этой задачи - такое решение категорически не рекомендуется.

bender
Сообщения: 37
Зарегистрирован: 24 фев 2005, 15:41

Сообщение bender » 12 июл 2005, 18:01

Работа с прогой предполагается в следующем режиме:
1) Запуск проги и открытие таблицы всех приборов хранящихся в БД с параметрами транзакции только чтение
2) Пользователь может либо открыть расширенные данные по конкретному прибору, опять же только для просмотра, либо инициировать считывание новых данных из Com-порта
3) В случае считывания данных, я планировал поставить флаг на приборе, который заблокирует любые попытки изменения, оновления, удаления данных связанных с этим прибором, кроме как в потоке, который поставил этот флаг
4) Несколько потоков планировалось использовать для того, чтобы можно было одновременно читать с нескольких портов
5) По окончании считывания и подтверждения пользователем необходимости сохранить данные в БД, запускалась бы транзакция на запись изменений и сброс флага занятого прибора. После завершения транзакция убивалась бы.
6) После всего этого необходимо оповестить каким-то образом все приложения, что данные по прибору изменились, а приложения в свою очередь приняли бы меры обновления соответствующих наборов данных. И опять работа с БД вернулась бы в режим просмотра.

И еще выделить в отдельные потоки все это считывание меня заставил тот факт, что я не знаю какие приборы будут в будущем, а постоянно переделывать приложение нехочется, вот я и пробую вынести работу с конкретным прибором в отдельную dll, которая цепляется динамически и которая полностью обеспечивает: считывание данных с прибора, запись данных в БД (в том числе контроль необходимых таблиц в БД), и выборку данных из БД.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 12 июл 2005, 18:12

рискну предположить, что ответом тебе будет тишина.

единственное, что могу тебе предложить - попробуй представить себе, что твоя аппликуха падает или сервер становится недоступен после пункта 1, 2, 3... и так до конца.

Вообще интересно. Это приложение (одно) будет у нескольких операторов? То есть, кто захотел - тыкнул в порт, считал данные, залил в БД? бардак какой то.... и что это за приборы, с корорых данные можно читать, а можно и не читать...

Ответить