Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Работа с БД в отдельном треде. [D7, XP]


Страницы:   1 2 3 4

Alex_C ©   (2012-03-11 11:52:00) 

В продолжении темы о необходимости нескольких ADOConnection, если работа с базой происходит в отдельном треде.
Вот есть какая проблема.
Дано ADO+Access.
Есть ClientDataSet - база клиентов фирмы.
Есть SpravDataSet - общий справочник жителей города N.
После того, как в ClientDataSet вносится новый клиент нужно в справочной базе SpravDataSet проверить, есть ли такой человек, если есть - отметить, что он теперь клиент фирмы.
Делаем это на событие AfterPost для ClientDataSet.
Дабы не происходило зависания программы при поиске соответствующей записи в базе справочника SpravDataSet , было принято решение работу с ним вынести в отдельный тред.
В отдельном треде создаем свой ADOConnection и ADODataSet для соединения с базой справочника. Делаем необходимые корректировки в базе - тут все ок, корректировки проходят как надо.
Теперь нам нужно обновить содержание окна, которое содержит таблицу со SpravDataSet . Для этого перед завершением работы треда вызываем метод Synchronize, в котором делаем  

SpravDataSet.CommandText := 'SELECT * FROM...'
SpravDataSet.Active := True;

И видим, что у нас отображаются "старые" данные по справочнику, без учета внесенных в треде изменений.
Если же затем мы вручную, по кнопке выполним код

SpravDataSet.CommandText := 'SELECT * FROM...'
SpravDataSet.Active := True;

то видим, что все изменения внеслись.
Вопрос: как сделать так, чтоб изменения были видны из метода Synchronize?


Alex_C   (2012-03-11 16:14:00) [41]


> что отдельный поток со своим коннектом все-таки нужен, то
> надо внимательно отследить, где и когда этот поток коммитит
> свою транзакцию - ведь пока он ее не закоммитит, другие
> коннекты изменений не увидят.


Совершенно верно - это я и хочу понять!


> настроены соответствующим образом уровни изоляции.


ilCursorStability установлены.


sniknik   (2012-03-11 16:09:00) [42]

> Кстати а как в данном случае правильно?
в данном случае поток НЕ НУЖЕН, максимум в пару запросов все решается. если вообще есть что решать (цель все этого? нафига при старте менять все значения, а после "только те, что нужны.").  

> Если, конечно, не настроены соответствующим образом уровни изоляции.
в ADO + Jet, уровни изоляции это отдельные COM объекты на каждое подключение (о чем я ему говорил уже). т.е. сделал отдельный... и жди пока он данные в файл скинет чтобы другой мог перечитать...
а вот с асинхронностью, когда он сам потоки делает, там все в порядке, сам делает, сам разбирается, что где, может и из буфера прочитать.


Юрий Зотов   (2012-03-11 16:02:00) [43]

> пока он ее не закоммитит, другие коннекты изменений не увидят

Если, конечно, не настроены соответствующим образом уровни изоляции.


Alex_C   (2012-03-11 16:02:00) [44]


> он думает так не будет "закачки всего", правильно в общем
> то, для access, но для этого нужно соблюсти все условия.
> ..
> к примеру не пользоваться  RecordCount, т.к. встречая его
> ADO начнет закачку чисто посчитать. (сработает как fetch
> al)l, насколько помню)


Совершенно верно так я и думаю.


> не пользоваться  RecordCount, т.к. встречая его ADO начнет
> закачку чисто посчитать.


Проверял по времени - вроде как даже при его использовании все равно существенно быстрее, если при большой бд делать clUseClient.


Юрий Зотов   (2012-03-11 15:59:00) [45]


> Alex_C   (11.03.12 15:41) [9]
> это все так считают, что следует избегать
> рабоать с БД в отдельном треде?

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

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

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


Alex_C   (2012-03-11 15:59:00) [46]


> Почему clUseServer


Пробовал и clUseClient - но разницы не было.
Кстати а как в данном случае правильно?


sniknik   (2012-03-11 15:59:00) [47]

> Почему clUseServer?
он думает так не будет "закачки всего", правильно в общем то, для access, но для этого нужно соблюсти все условия...
к примеру не пользоваться  RecordCount, т.к. встречая его ADO начнет закачку чисто посчитать. (сработает как fetch al)l, насколько помню)

а вот почему прямые обращения из потока типа MainForm.LogName?


Alex_C   (2012-03-11 15:56:00) [48]


> вот этот апдейт *всех* записей таблицы, он зачем?


Не всех, а в соответствии с условием

     if FCountry = '' then
       CommandText := 'SELECT * FROM SpotTable'
     else
       CommandText := 'SELECT * FROM SpotTable WHERE Country = ' + QuotedStr(FCountry);
     Active := True;


Все записи обходятся только при открытии БД - в остальных случаях только те, что нужны.


Anatoly Podgoretsky   (2012-03-11 15:54:00) [49]

> Alex_C  (11.03.2012 15:46:12)  [12]

Почему clUseServer?


Alex_C   (2012-03-11 15:52:00) [50]


> ламер.

Да. Ламер. И пишу в соответствующей теме. Если тебе это так не приятно - просто пройди мимо.


RWolf   (2012-03-11 15:51:00) [51]

       First;
       while not Eof do
       begin
         Edit;
         FieldByName('IsNewCountry').AsInteger :=
           GetCountryStatus(FieldByName('DXCall').AsString,
               FieldByName('BandADIF').AsString,
               FieldByName('Mode').AsString);
         Post;
         Next;
       end;


вот этот апдейт *всех* записей таблицы, он зачем?


Alex_C   (2012-03-11 15:51:00) [52]

Небольшое объяснение к коду:
SpotTable - это собственно та таблица, которую нежно изменять. Как видно из кода, при некоторых условиях приходится изменять все данные в этой таблице. При некоторых - только часть.
Для каждой выбранной из SpotTable записи необходимо проверить/изменить ее статус.
В итоге время получается около 2 сек.


sniknik   (2012-03-11 15:48:00) [53]

> я так понимаю ты считаешь что работать с БД в отдельном треде не следует. Ок! Я твою точку зрения понял.
опять ДОМЫСЛЫ. ламер.


RWolf   (2012-03-11 15:47:00) [54]


> это все так считают, что следует избегать рабоать с БД в
> отдельном треде?

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


Alex_C   (2012-03-11 15:46:00) [55]

ок! вот реальный код.


procedure TRecalcColorThread.Execute;
var
 FDataSet: TADODataSet;
 FLogDataSet: TADODataSet;
 S: string;

 {$I GetCountryIndex.pas}

begin
 CoInitialize(nil);
 SpotMachineForm.SpotResLock.Lock;
 try
   FDataSet := TADODataSet.Create(nil);
   with FDataSet do
   begin
     ConnectionString := DataBaseConnectionString;
     CursorLocation := clUseServer;

     if FCountry = '' then
       CommandText := 'SELECT * FROM SpotTable'
     else
       CommandText := 'SELECT * FROM SpotTable WHERE Country = ' + QuotedStr(FCountry);
     Active := True;
     if RecordCount > 0 then
     begin
       FLogDataSet := TADODataSet.Create(nil);
       with FLogDataSet do
       begin
         //Connection := FLogConnection;
         ConnectionString := LogConnectionString;
         CursorLocation := clUseServer;
         S := '';
         if PaperQSLR  then
           S := 'QSLR';
         if LoTWQSLR then
         begin
           if S = '' then
             S := 'LoTWR'
           else
             S := S + '+LoTWR';
         end;
         if eQSLR then
         begin
           if S = '' then
             S := 'eQSLR'
           else
             S := S + '+eQSLR';
         end;
         if S = '' then
           S := '0';
         if FCountry = '' then
           CommandText := 'SELECT Country, BandADIF, Mode, SUM(' + S + ') AS QSL ' +
             'FROM ' + MainForm.LogName + ' WHERE Country <> ' + QuotedStr('') +
             'GROUP BY Country, BandADIF, Mode ORDER BY Country '
         else
           CommandText := 'SELECT Country, BandADIF, Mode, SUM(' + S + ') AS QSL ' +
             'FROM ' + MainForm.LogName + ' WHERE Country = ' + QuotedStr(FCountry) +
             'GROUP BY Country, BandADIF, Mode ORDER BY Country ';
         Active := True;
       end;
       //**********************************************************************
       First;
       while not Eof do
       begin
         Edit;
         FieldByName('IsNewCountry').AsInteger :=
           GetCountryStatus(FieldByName('DXCall').AsString,
               FieldByName('BandADIF').AsString,
               FieldByName('Mode').AsString);
         Post;
         Next;
       end;
       FreeAndNil(FLogDataSet);
     end;
   end;
 finally
   FreeAndNil(FDataSet);
   SpotMachineForm.SpotResLock.UnLock;
   CoUninitialize;
 end;
 Synchronize(RefreshWithSpotWindow);
end;


sniknik   (2012-03-11 15:46:00) [56]

> проверка
"усложнил"
UPDATE n_street
SET Name = 'Межевая'
WHERE Code = '47010011003000600'

на более объемной таблице - 899615 записей, индекс "шире". время тоже - 00:00.000.
НА ХРЕНА ПОТОКИ?

> согласно этой рекоммендации.
в рекомендации может быть все идеально, но главный глюк не рекомендации/справка/система/объект/компонент, и т.д., а ТЫ. именно ты делаешь глюки, именно ТВОЙ код нужно проверять, пусть он и сделан по самой расчудесной рекомендации.

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


Alex_C   (2012-03-11 15:42:00) [57]

[9] пост относился к sniknik.


Alex_C   (2012-03-11 15:41:00) [58]

Послушай, я хочу не в данной конкретной задаче, а для себя понять, как работать в отдельном треде с БД. Работа с БД в отдельном треде не считается чем то плохим.
Вот сейчас у меня возник конкретный вопрос: я в отдельном треде изменил данные. Теперь эти измененные данные я хочу отобразить в таблице.
По твоему негативному к этому отношения, я так понимаю ты считаешь что работать с БД в отдельном треде не следует. Ок! Я твою точку зрения понял.
Теперь вопрос к другим: это все так считают, что следует избегать рабоать с БД в отдельном треде?


Anatoly Podgoretsky   (2012-03-11 15:39:00) [59]

Кроме того никакой конкретики, код не приведен. Разговор ни о чем.


Anatoly Podgoretsky   (2012-03-11 15:37:00) [60]


> Да, саму работу в отдельном треде делал согласно этой рекоммендации.

CoUninitialize не защищен секцией try, код опасный


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо