Не обновляется НД после Insert
Модератор: kdv
Не обновляется НД после Insert
Может ламерский вопрос, но уже который час не могу обновить набор данных, а именно:
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() как-то некрасиво, где я ошибаюсь?
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() как-то некрасиво, где я ошибаюсь?
Re: Не обновляется НД после Insert
Через Refresh не пройдёт,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() как-то некрасиво, где я ошибаюсь?
хочешь узнать почему: создай IBDATASET в SELECTSQL укажи
то,что тебе надо и сгенери запросы.
см. REFRESH SQL.
Re: Не обновляется НД после Insert
То есть это получится связка IBQuery+IBUpdateSQL, а если я хочу в отдельном потоке, при помощи своего IBQuery или IBSQL (в поток передается указатель на IBDatabase, созданный в основном потоке)McArty писал(а):Через Refresh не пройдёт,
хочешь узнать почему: создай IBDATASET в SELECTSQL укажи
то,что тебе надо и сгенери запросы.
см. REFRESH SQL.
Раньше юзал IBO, там Refresh работал, и еще там был Refresh() для транзакции.
Мужики, я голову сломал, перечитал несколько факов по транзакциям и 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()
Переделал приложение, так, что теперь есть две транзакции 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()
Ну нету у TIBQuery проперти RefreshSQL, нее-ту. И искусственным интеллектом для построения оного оно не обладает. Метод Refresh остался как затычка из-за происхождения оного компонента из племени TDataSet. TIBDataSet для чтения использовать и прописать ему RefreshSQL религия не позволяет или таковы требования ТЗ? Тогда переоткрывай TIBQuery и позиционируйся на запись через букмарки или локейтом.
за faq ответишь?
ibx.htm - это НЕ faq. Собственно, чего ты привязался к IBQuery?
При использовании IBDatabase (IBX) в многопоточных (multithreaded) приложениях, в том числе с web- или com-серверами, нужно соблюдать следующие правила:
1. соединение с БД не должно быть "локальным". То есть не c:\dir\data.gdb, а сетевым - localhost:c:\dir\data.gdb.
2. в одном thread допускается работа только с одним IBDatabase. Причем соединение с сервером должно осуществляться в главном thread, после чего допускается работа в контексте коннекта в отдельном thread.
Попытка осуществить работу с одним коннектом из разных threads может быть успешной, если использовать блокировки thread при обращении к этому коннекту (на мютексах, семафорах и т.п.). Но в результате работа всего приложения будет не многопоточной, то есть, превратится в псевдо-многопоточное по причине блокировок между threads при работе с одиним коннектом.

какие потоки? цитирую ibx.htm:То есть это получится связка IBQuery+IBUpdateSQL, а если я хочу в отдельном потоке, при помощи своего IBQuery или IBSQL (в поток передается указатель на IBDatabase, созданный в основном потоке)
При использовании 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 раз.
Читал я эти правила и их соблюдаю:
1) соединение через полное имя "сервер:путь"
2) в каждый дочерний поток я передаю указатель на один единственный IBDatabase, который создан и открыт в основном потоке приложения
3) синхронизация потоков будет осуществляться через TThread->Synchronize()
Но проблема пока не в этом, а в том что, цитата из статьи "Транзакции в InterBase": nowait read_committed rec_version
именно такой уровень изоляции будет видеть изменения, производимые другими транзакциями (но не раньше их завершения по commit), и минимально конфликтовать при обновлении или удалении данных.
Первая транзакция читает данные из таблицы, вторая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат) Помогает единственное, закрыть и открыть IBQuery, но как-то это не клеится с цитатой выше о видимости транзакций (Если оно так и должно работать, то я вопросов больше не имею)
1) соединение через полное имя "сервер:путь"
2) в каждый дочерний поток я передаю указатель на один единственный IBDatabase, который создан и открыт в основном потоке приложения
3) синхронизация потоков будет осуществляться через TThread->Synchronize()
Но проблема пока не в этом, а в том что, цитата из статьи "Транзакции в InterBase": nowait read_committed rec_version
именно такой уровень изоляции будет видеть изменения, производимые другими транзакциями (но не раньше их завершения по commit), и минимально конфликтовать при обновлении или удалении данных.
Первая транзакция читает данные из таблицы, вторая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат) Помогает единственное, закрыть и открыть IBQuery, но как-то это не клеится с цитатой выше о видимости транзакций (Если оно так и должно работать, то я вопросов больше не имею)
ну, чем ты там потоки между собой синхронизируешь, это твое личное дело. Другое дело, что в одном коннекте 2 запроса в разных потоках выполнять нельзя.3) синхронизация потоков будет осуществляться через TThread->Synchronize()
читаешь не глазами, и не понимаешь вообще. Refresh обновляет ТЕКУЩУЮ ЗАПИСЬ ДАТАСЕТА!!! Чтобы увидеть данные, вставленные другими запросами, транзакциями, коннектами, приложениями - нужно ПЕРЕВЫПОЛНИТЬ ЗАПРОС (Close/Open).которая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат)
Что тут непонятного?
опять цитирую ibx.htm
отсюда разве неясно?RefreshSQL - запрос для обновления текущей строки. Должен содержать условие отбора по первичному ключу или подобное, для выборки одной записи.
Если речь не об stateless application server with connections pool, то явно отдаёт проктологией. Но это не суть.bender писал(а):Читал я эти правила и их соблюдаю:
1) соединение через полное имя "сервер:путь"
2) в каждый дочерний поток я передаю указатель на один единственный IBDatabase, который создан и открыт в основном потоке приложения
3) синхронизация потоков будет осуществляться через TThread->Synchronize()
Таки это правда.bender писал(а): Но проблема пока не в этом, а в том что, цитата из статьи "Транзакции в InterBase": nowait read_committed rec_version
именно такой уровень изоляции будет видеть изменения, производимые другими транзакциями (но не раньше их завершения по commit), и минимально конфликтовать при обновлении или удалении данных.
Насчёт применения IBUpdateSQL не скажу, к проктологии не склонен, так что опыта нет, но если с IBDataSet то же самое - это значит, что либо неправильно написан RefreshSQL, либо коммитится не та транзакция, либо коммитится не вовремя либо ещё что-то не так в приложении.bender писал(а): Первая транзакция читает данные из таблицы, вторая пишет их туда и закрывается Commit'ом, делаю Refresh() и первая транзакция как не видела вставленной записи, так и не видит (у меня к IBQuery присоединен IBUpdateSQL с параметром RefreshSQL, кстати пробовал вместо IBQuery+IBUpdateSQL использовать IBDataSet, тот же результат) Помогает единственное, закрыть и открыть IBQuery, но как-то это не клеится с цитатой выше о видимости транзакций (Если оно так и должно работать, то я вопросов больше не имею)
Теперь все стало на свои места, просто раньше пользовался IBO и там Refresh обновлял все записи, как если бы я сделал Close-Open.kdv писал(а): читаешь не глазами, и не понимаешь вообще. Refresh обновляет ТЕКУЩУЮ ЗАПИСЬ ДАТАСЕТА!!! Чтобы увидеть данные, вставленные другими запросами, транзакциями, коннектами, приложениями - нужно ПЕРЕВЫПОЛНИТЬ ЗАПРОС (Close/Open).
Что тут непонятного?
Спасибо за ответ, остается непонятным один момент:
Допустим есть два приложения, оба открыли один и тот же набор данных, но каждое в своем коннекте (допустим эти приложения запущены на разных компьютерах). Через какое-то время первое приложение меняет набор данных и фиксирует его Commit'ом, для этого приложения не трудно опознать момент, когда необходимо переоткрыть набор данных, а как быть с приложением на другом компьютере?
Дима. Что ты наделал. Сейчас в полку гридорефрешителей по евентам прибудет. И dimitr кого-нибудь наконец застрелит. Я-то уже почти выработал иммунитет.kdv писал(а):а никак. в многопользовательской среде все вокруг меняют какие-нибудь данные. Не будешь же ты постоянно все рефрешить. А для оповещения о применении изменений существуют евенты.а как быть с приложением на другом компьютере?
2 товарищ bender:
Про то, что ты ожидал от Refresh переотрытия запроса, я не подумал. Если функция этого резалтсета - отражать состояние какого-то _процесса_, то запрос переоткрывают по таймеру. Если же это список каких-то объектов для выбора и редактирования, и одновременное редактирование одной записи недопустимо и маловероятно, то в момент начала редактирования стартуют снапшот, в нём перечитывают именно эту запись, выполняют редактирование и попытку модификации в базе, коммитят снапшот, рефрешат строку в читающей транзакции. Тогда в случае одновременного редактирования гарантирован конфликт и его обрабатываем по вкусу. Если таковое событие очень вероятно, то на старте редактирования пытаются сразу установить пессимистическую блокировку записи, чтоб конфликт был до, а не после редактирования.
да я видел, к чему это идет. но.... например, не будешь же умалчивать что в сервере есть то или это. Вон, в треде про 40-гиговую базу - 3.5 миллиона транзакций в сутки. Как бы, никто не запрещает, я из-за ошибки разработчика видел и 6 миллионов в сутки...Дима. Что ты наделал. Сейчас в полку гридорефрешителей по евентам прибудет. И dimitr кого-нибудь наконец застрелит. Я-то уже почти выработал иммунитет.
-
- Заслуженный разработчик
- Сообщения: 644
- Зарегистрирован: 15 фев 2005, 11:34
Задача предполагается такая:
Есть БД приборов, данные по которым беруться из самих приборов, путем считывания через (допустим) Com-порт. Для работы с конкретным прибором создается свой поток, в который передается указатель на IBDatabase, далее в потоке в критической секции меняется (0->1) поле в таблице приборов, отвечающее за то, что прибор считывается каким-то потоком (и он соответственно становится недоступным другим потокам и пользователям). Происходит считывание данных, которые записываются в БД (опять же в критической секции) и посылается Event всем приложениям подписанным на этот Event, после чего происходит рефреш необходимых гридов. Так будет корректно? Кстати, а чем плох рефреш грида по событию?
Есть БД приборов, данные по которым беруться из самих приборов, путем считывания через (допустим) Com-порт. Для работы с конкретным прибором создается свой поток, в который передается указатель на IBDatabase, далее в потоке в критической секции меняется (0->1) поле в таблице приборов, отвечающее за то, что прибор считывается каким-то потоком (и он соответственно становится недоступным другим потокам и пользователям). Происходит считывание данных, которые записываются в БД (опять же в критической секции) и посылается Event всем приложениям подписанным на этот Event, после чего происходит рефреш необходимых гридов. Так будет корректно? Кстати, а чем плох рефреш грида по событию?
почитать тут, или в e.p.i эта тема не раз обсуждалась.
значит, должно быть так:
1. твоя софтина из ком-порта записывает данные В ФАЙЛ. Никаких баз данных.
2. другая софтина подчитывает данные ИЗ ФАЙЛА, и закидывает в базу. Дальше файл можно перемещать как обработанный или ошибочный в спец-каталоги, и архивировать.
3. никоим образом не рефрешить по евентам.
объясняю. 1+2 гарантируют что серверу БД не надо работать 24x7, и что при любом сбое (кроме сбоя пункта 1) данные не пропадут.
никакие тут потоки вообще не нужны и даже вредны.
пункт 3 - с какой частотой приходят данные, и кому с этой частотой их надо обновлять???
добавлю, что конечно, исходная идея смотрится "красиво" - потоки там, евенты, все дела. Но в реальной жизни это НЕ РАБОТАЕТ. То есть, потоки работают, евенты, но в такой комбинации и для этой задачи - такое решение категорически не рекомендуется.
значит, должно быть так:
1. твоя софтина из ком-порта записывает данные В ФАЙЛ. Никаких баз данных.
2. другая софтина подчитывает данные ИЗ ФАЙЛА, и закидывает в базу. Дальше файл можно перемещать как обработанный или ошибочный в спец-каталоги, и архивировать.
3. никоим образом не рефрешить по евентам.
объясняю. 1+2 гарантируют что серверу БД не надо работать 24x7, и что при любом сбое (кроме сбоя пункта 1) данные не пропадут.
никакие тут потоки вообще не нужны и даже вредны.
пункт 3 - с какой частотой приходят данные, и кому с этой частотой их надо обновлять???
добавлю, что конечно, исходная идея смотрится "красиво" - потоки там, евенты, все дела. Но в реальной жизни это НЕ РАБОТАЕТ. То есть, потоки работают, евенты, но в такой комбинации и для этой задачи - такое решение категорически не рекомендуется.
Работа с прогой предполагается в следующем режиме:
1) Запуск проги и открытие таблицы всех приборов хранящихся в БД с параметрами транзакции только чтение
2) Пользователь может либо открыть расширенные данные по конкретному прибору, опять же только для просмотра, либо инициировать считывание новых данных из Com-порта
3) В случае считывания данных, я планировал поставить флаг на приборе, который заблокирует любые попытки изменения, оновления, удаления данных связанных с этим прибором, кроме как в потоке, который поставил этот флаг
4) Несколько потоков планировалось использовать для того, чтобы можно было одновременно читать с нескольких портов
5) По окончании считывания и подтверждения пользователем необходимости сохранить данные в БД, запускалась бы транзакция на запись изменений и сброс флага занятого прибора. После завершения транзакция убивалась бы.
6) После всего этого необходимо оповестить каким-то образом все приложения, что данные по прибору изменились, а приложения в свою очередь приняли бы меры обновления соответствующих наборов данных. И опять работа с БД вернулась бы в режим просмотра.
И еще выделить в отдельные потоки все это считывание меня заставил тот факт, что я не знаю какие приборы будут в будущем, а постоянно переделывать приложение нехочется, вот я и пробую вынести работу с конкретным прибором в отдельную dll, которая цепляется динамически и которая полностью обеспечивает: считывание данных с прибора, запись данных в БД (в том числе контроль необходимых таблиц в БД), и выборку данных из БД.
1) Запуск проги и открытие таблицы всех приборов хранящихся в БД с параметрами транзакции только чтение
2) Пользователь может либо открыть расширенные данные по конкретному прибору, опять же только для просмотра, либо инициировать считывание новых данных из Com-порта
3) В случае считывания данных, я планировал поставить флаг на приборе, который заблокирует любые попытки изменения, оновления, удаления данных связанных с этим прибором, кроме как в потоке, который поставил этот флаг
4) Несколько потоков планировалось использовать для того, чтобы можно было одновременно читать с нескольких портов
5) По окончании считывания и подтверждения пользователем необходимости сохранить данные в БД, запускалась бы транзакция на запись изменений и сброс флага занятого прибора. После завершения транзакция убивалась бы.
6) После всего этого необходимо оповестить каким-то образом все приложения, что данные по прибору изменились, а приложения в свою очередь приняли бы меры обновления соответствующих наборов данных. И опять работа с БД вернулась бы в режим просмотра.
И еще выделить в отдельные потоки все это считывание меня заставил тот факт, что я не знаю какие приборы будут в будущем, а постоянно переделывать приложение нехочется, вот я и пробую вынести работу с конкретным прибором в отдельную dll, которая цепляется динамически и которая полностью обеспечивает: считывание данных с прибора, запись данных в БД (в том числе контроль необходимых таблиц в БД), и выборку данных из БД.
рискну предположить, что ответом тебе будет тишина.
единственное, что могу тебе предложить - попробуй представить себе, что твоя аппликуха падает или сервер становится недоступен после пункта 1, 2, 3... и так до конца.
Вообще интересно. Это приложение (одно) будет у нескольких операторов? То есть, кто захотел - тыкнул в порт, считал данные, залил в БД? бардак какой то.... и что это за приборы, с корорых данные можно читать, а можно и не читать...
единственное, что могу тебе предложить - попробуй представить себе, что твоя аппликуха падает или сервер становится недоступен после пункта 1, 2, 3... и так до конца.
Вообще интересно. Это приложение (одно) будет у нескольких операторов? То есть, кто захотел - тыкнул в порт, считал данные, залил в БД? бардак какой то.... и что это за приборы, с корорых данные можно читать, а можно и не читать...