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-14 14:32:00) [1]

Я вот спросить хочу: может я когда то тебя чем то обидел? Или ты просто обижен жизнью, а на мне пытаешься отыграться? Ты чего тут кричишь?
Я наверное давно должен быть обиженным и уйти. Но я на людей привык не обижаться, по этому тебе отвечу.


> для каждой таблицы отдельную базу держишь


У меня в логе всего 2 БД - в одной сам лог и относящиеся к нему справочные таблицы(диапазоны, модуляция) и вторая БД - там около 15 справочных БД.
Все как и обсуждалось давно.
Ты вот тут чего х.. несешь?


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


Я тебе еще раз говорю - там все только то, что нужно. Как ты вообще можешь судить "о вкусе фуагра", если ты его не ел?


> клиент серверные методы, sql, на клиент серверном базе (движке)
> игнорируешь, пользуешься навигационными.


Предупреждаю: адрес этой темы я дал еще нескольким проф программистам - я у них давно советы спрашиваю.
Ты реально думаешь что АБСОЛЮТНО ВСЕ можно сделать с помощью SQL-запроса? Тем, кто читает эту тему - а они так такого SQL-запроса сделать не смогли (хотя тоже говорили, что смогут - очень интеренсно). Не испугаешься ответить за свои слова - давай мне на мыло. Напишу полностью всю задачу. От меня и от моих знакомых - пару ящиков пива тебе обеспечены, если сделаешь.


> об ускорении, делаешь все наиболее тормозными способами


Ну учитывая, что быстрее, чем у меня лог ни у кого не работает... Наверное я гений! )))


> чуть ли не силком реальный код


Я спросил конкретный вопрос. Я не спрашивал - как делать. Я спросил - как сделать именно так.


> ЭТО ВЫ НЕ ПОНИМАЕТЕ


Чего кричишь? :)


> но тем не менее другого ты от меня


Помнишь ты привел мне пример про качков? Про зеркало? Помнишь?
Так вот: учитывая, что в 20 лет у меня был КМС по атлетическому троеборью скажу тебе так:
у качков самое доброжелательное отношение к тому, кто спрашивает твоего совета. Сильные люди - они добрые. :) Это слабаки пытаются хамя свое сомомнение поднять.
И тем не менее: я даю тебе шанс - миши мне на емайл - дам тебе полную катрину виденья. Поможешь - молодец. А так.... говорить все умеют.

И тем не менее:
Еще раз хочу выразить призательность многим присутствующим тут форумчанам за помощь! Никогда не забуду помощь Сергей М. в организации работе телнета - сколько лет прошло, а лучше чем в моей программе телнет ни у кого не работает))))


sniknik   (2012-03-13 17:51:00) [2]

> я знаю всю специфику ...
и поэтому молодец, что для каждой таблицы отдельную базу держишь! так держать!
и молодец, что расчетные данные, которые в любой момент получить можно, в базу пихаешь, грузишь ее .
молодец, что клиент серверные методы, sql, на клиент серверном базе (движке) игнорируешь, пользуешься навигационными.
молодец, что говоря об ускорении, делаешь все наиболее тормозными способами, не учитывая специфику используемых компонент.

реально М О Л О Д Е Ц !!!

(хотя вообще то все выше сарказм, а то еще поймешь "по своему")

> "добил" тему до конца :)
"добил"... ага, да тебя чуть ли не силком реальный код, а не "рассуждения" о нем, показать заставили. а в реальном, сам наконец то увидел, а не увидел бы через пару минут мое прочитал...

ты сколько это "бил" чтобы "добить"? а мне пару несколько минут понадобилось. но тем не менее другого ты от меня (и других тут тоже) не воспринимаешь... типа ЭТО ВЫ НЕ ПОНИМАЕТЕ.
!!!???
да как хочешь, заблуждайся дальше.


Alex_C   (2012-03-13 17:25:00) [3]


> придуманная из-за кривой логики


Раз проблема решилась, немного не в тему, но думаю для сведения интересно:
- прикольно, но сегодня утром ко мне в аську постучал старый знакомый из другого города. Тоже радиолюбитель и тоже автор лога для радиолюбителей. Только в отличии от меня, он профессиональный программист, специализирующийся на БД (причем очень неплохой программист).
Самое смешное, что он хотел обсудить проблему занесения спотов в базу (то, что я как раз тут и выяснял).
Будучи профессиональным программистом, базу он выбрал себе FireBird.
Так вот - тут как раз с ним обсуждали вопросы логики работы этой базы. Я ему про эту тему рассказал.
Так вот он поугарал и мне сказал: если б я не знал, что ты за программу пишешь, я был бы на стороне  sniknik, но т.к. я знаю всю специфику - молодец что "добил" тему до конца :) Другого тут решения быть не может.
Теперь буду ждать выходных - будут соревнования, проверю свой лог при большом количестве приходящих спотов.


sniknik   (2012-03-13 12:48:00) [4]

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


sniknik   (2012-03-13 12:47:00) [5]

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


Anatoly Podgoretsky   (2012-03-13 12:46:00) [6]

> Alex_C  (13.03.2012 12:29:55)  [55]

Что же ты хочешь когда у тебя два соединения.


sniknik   (2012-03-13 12:46:00) [7]

нда, опоздал.
> RefreshCache делается читающей стороной...


Alex_C   (2012-03-13 12:46:00) [8]

Да, вот еще информация, на которую следует обратить внимание:


JetEngine object's RefreshCache Method
There is a separate read-cache for each connection object. Calling the RefreshCache method of the JetEngine object, as exposed by the Microsoft Jet and Replication Objects type library, immediately refreshes the read-cache for the Connection objects passed as a method argument. The read-cache for all other Connection objects in the application are not affected.
Back to the top
"Jet OLEDB:Transaction Commit Mode" Connection Property
In Microsoft Jet 2.x and earlier, all writes were immediately committed. With Win32 and multi-threading, Microsoft Jet introduced a lazy-write mechanism. Setting this property to a value of 1 causes all transaction commits to be written immediately to disk for that Connection object. All other Connection objects are unaffected.

These methods are preferable to modifying registry values to get the same effect because you can precisely control where you need this value and they are more deterministic in operation. Global registry programs will adversely affect engine performance in other areas and in other applications.


sniknik   (2012-03-13 12:45:00) [9]

и кстати
ADOConnection1. BeginTrans; в некоторых случаях не работает, т.к. может быть локальным, а не от движка. пользуйся запросами. (одна из причин почему JRO мог не сработать, вторая в том что RefreshCache делается читающей стороной...)


Alex_C   (2012-03-13 12:43:00) [10]

Все! Проблема решена!
Все делается как я написал выше только


 JE := (CreateOleObject('JRO.JetEngine') as JetEngine);
 try
   JE.RefreshCache(ADOConnection2.ConnectionObject as ADODB_TLB._Connection);
 finally
   JE := nil;
 end;


RefreshCashe делается на ЧИТАЮЩИЙ  ADOConnect, а я его на пишущей ставил!

Кстати темя эта если ее погуглить весьма широко в инете обсуждается.
Для тех, кто боится быть .... привожу полный работающий код:


const
 ConnectionStr = 'Provider=Microsoft.Jet.OLEDB.4.0;Password="";User ID=Admin;'+
   'Data Source=db1.mdb;Mode=Share Deny None;Extended Properties="" ;'+
   'Locale Identifier=1049;Persist Security Info=True;Jet OLEDB:System database="" ;'+
   'Jet OLEDB:Registry Path="" ;Jet OLEDB:Database Password="" ;Jet OLEDB:Engine Type=5;'+
   'Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk Ops=2;'+
   'Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="" ;'+
   'Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;'+
   'Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False;' +
   'Jet OLEDB:Don''t copy locale on compact=False;';

var
 i: integer;

procedure TForm3.Button1Click(Sender: TObject);
begin
 with ADODataSet1 do
 begin
   Active := False;
   CommandText := 'SELECT * FROM LogTest';
   Active := True;
 end;
end;

procedure TForm3.Button2Click(Sender: TObject);
begin
 with ADODataSet2 do
 begin
   Active := False;
   CommandText := 'SELECT * FROM LogTest';
   Active := True;
 end;
end;

procedure TForm3.Button3Click(Sender: TObject);
var
 V: Variant;
 JE: JetEngine;
begin
 ADOConnection1.BeginTrans;
 {with ADODataSet1 do
 begin
   Append;
   FieldByName('Call').AsString := 'RX4HX' + IntToStr(i);
   FieldByName('DateQSO').AsDateTime := Now;
   FieldByName('BandQSO').AsString := IntToStr(i);
   Post;
 end;}

 with ADOCommand1 do
 begin
   CommandText := 'INSERT INTO LogTest (Call,DateQSO,BandQSO) ' +
     'VALUES(:Call,:DateQSO,:BandQSO)';
   Parameters.Items[0].DataType := ftString;
   Parameters.Items[0].Value := 'RX4HX' + IntToStr(i);
   Parameters.Items[1].DataType := ftDateTime;
   Parameters.Items[1].Value := Now;
   Parameters.Items[2].DataType := ftString;
   Parameters.Items[2].Value := IntToStr(i);
   Execute;
 end;
 ADOConnection1.CommitTrans;

 {V := CreateOleObject('JRO.JetEngine');
 try
   V.RefreshCache(ADOConnection1.ConnectionObject);
 finally
   V := 0;
 end;}
 {JE := (CreateOleObject('JRO.JetEngine') as JetEngine);
 try
   JE.RefreshCache(ADOConnection1.ConnectionObject as ADODB_TLB._Connection);
 finally
   JE := nil;
 end;}
 JE := (CreateOleObject('JRO.JetEngine') as JetEngine);
 try
   JE.RefreshCache(ADOConnection2.ConnectionObject as ADODB_TLB._Connection);
 finally
   JE := nil;
 end;
 Button1Click(nil);
 Button2Click(nil);
 Inc(i);
end;

procedure TForm3.Button4Click(Sender: TObject);
begin
 ADOCommand1.CommandText := 'DELETE * FROM LogTest';
 ADOCommand1.Execute;
 Button1Click(nil);
 Button2Click(nil);
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
 with ADOConnection1 do
 begin
   ConnectionString := ConnectionStr;
   LoginPrompt := False;
   Mode := cmShareDenyNone;
   Attributes := [];
   Open;
   Properties.Item['Jet OLEDB:Transaction Commit Mode'].Value := 1;
   Properties.Item['Jet OLEDB:Shared Async Delay'].Value := 0;
   Properties.Item['Jet OLEDB:User Commit Sync'].Value := 1;
   Properties.Item['Jet OLEDB:Implicit Commit Sync'].Value := 1;
   Properties.Item['Jet OLEDB:Flush Transaction Timeout'].Value := 0;
 end;
 with ADOConnection2 do
 begin
   ConnectionString := ConnectionStr;
   LoginPrompt := False;
   Mode := cmShareDenyNone;
   Attributes := [];
   Open;
   Properties.Item['Jet OLEDB:Transaction Commit Mode'].Value := 1;
   Properties.Item['Jet OLEDB:Shared Async Delay'].Value := 0;
   Properties.Item['Jet OLEDB:User Commit Sync'].Value := 1;
   Properties.Item['Jet OLEDB:Implicit Commit Sync'].Value := 1;
   Properties.Item['Jet OLEDB:Flush Transaction Timeout'].Value := 0;
 end;
 i := 1;
 Button1Click(nil);
 Button2Click(nil);
end;

end.


sniknik   (2012-03-13 12:40:00) [11]

ты по моему не слышишь/игнорируешь того чего тебе говорят...
COM  объект, каждый коннект. и т.д. sniknik ©   (11.03.12 16:09) [25] перечитай.

не? не доходит?

> Мой вопрос КОНКРЕТНО по этому ПОЛНОМУ примеру - как сделать , чтоб новая запись появлялась сразу и в DBGrid2?
сделать все через 1 коннект.


Alex_C   (2012-03-13 12:29:00) [12]


>  "выносишь в тред" делается тысячную долю секунды


Вот я одно не пойму - ты даже не вникая в суть проблемы все время мне здесь хамишь.
Нет никаких "тысячных" долей - есть задержка в секунды при приходе большого кол-ва спотов.
Эта проблема не только у меня - а еще и у десятка программистов, пишущих лог для радиолюбителей. А среди них много профи в программировании. Каждый решает эту задачу по своему - но так пока до конца никто ее "идеально хорошо" не смог решить.

Привожу ПОЛНЫЙ код примера.
Есть форма, на ней ADOConnection1+ADODataSet1+DBGrid1, ADOConnection2+ADODataSet2+DBGrid2, ADOConnection1+ADOCommand1.


var
 i: integer;

procedure TForm3.Button1Click(Sender: TObject);
begin
 with ADODataSet1 do
 begin
   Active := False;
   CommandText := 'SELECT * FROM LogTest';
   Active := True;
 end;
end;

procedure TForm3.Button2Click(Sender: TObject);
begin
 with ADODataSet2 do
 begin
   Active := False;
   CommandText := 'SELECT * FROM LogTest';
   Active := True;
 end;
end;

procedure TForm3.Button3Click(Sender: TObject);
var
 V: Variant;
 JE: JetEngine;
begin
 ADOConnection1.BeginTrans;
 {with ADODataSet1 do
 begin
   Append;
   FieldByName('Call').AsString := 'RX4HX' + IntToStr(i);
   FieldByName('DateQSO').AsDateTime := Now;
   FieldByName('BandQSO').AsString := IntToStr(i);
   Post;
 end;}

 with ADOCommand1 do
 begin
   CommandText := 'INSERT INTO LogTest (Call,DateQSO,BandQSO) ' +
     'VALUES(:Call,:DateQSO,:BandQSO)';
   Parameters.Items[0].DataType := ftString;
   Parameters.Items[0].Value := 'RX4HX' + IntToStr(i);
   Parameters.Items[1].DataType := ftDateTime;
   Parameters.Items[1].Value := Now;
   Parameters.Items[2].DataType := ftString;
   Parameters.Items[2].Value := IntToStr(i);
   Execute;
 end;
 ADOConnection1.CommitTrans;

 {V := CreateOleObject('JRO.JetEngine');
 try
   V.RefreshCache(ADOConnection1.ConnectionObject);
 finally
   V := 0;
 end;}
 JE := (CreateOleObject('JRO.JetEngine') as JetEngine);
 try
   JE.RefreshCache(ADOConnection1.ConnectionObject as ADODB_TLB._Connection);
 finally
   JE := nil;
 end;
 Button1Click(nil);
 Button2Click(nil);
 Inc(i);
end;

procedure TForm3.Button4Click(Sender: TObject);
begin
 ADOCommand1.CommandText := 'DELETE * FROM LogTest';
 ADOCommand1.Execute;
 Button1Click(nil);
 Button2Click(nil);
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
 with ADOConnection1 do
 begin
   ConnectionString := ConnectionStr;
   LoginPrompt := False;
   Mode := cmShareDenyNone;
   Attributes := [];
   Open;
 end;
 with ADOConnection2 do
 begin
   ConnectionString := ConnectionStr;
   LoginPrompt := False;
   Mode := cmShareDenyNone;
   Attributes := [];
   Open;
 end;
 i := 1;
 Button1Click(nil);
 Button2Click(nil);
end;



Нажимаем Button3. Что мы видим - в DBGrid1 - есть новая запись. В DBGrid2 - нет. Ждем 5 сек - жмем Button2 - новая запись появилась и в DBGrid2.

Мой вопрос КОНКРЕТНО по этому ПОЛНОМУ примеру - как сделать , чтоб новая запись появлялась сразу и в DBGrid2?


Anatoly Podgoretsky   (2012-03-13 10:32:00) [13]

> sniknik  (13.03.2012 09:44:53)  [53]

Инструмент называется шустрый программист с прибамбасами


sniknik   (2012-03-13 09:44:00) [14]

> ну так, может, использовать инструмент пошустрее?
в чьих руках?
в начале показывал пример, то что он делает (говорит, т.к. ничего для проверки нет) делается 2 сек, у меня даже не определяется т.к. отображаемая шкала времени кончается на тысячной доле секунды.

или ты имеешь в виду вместо автора взять программиста? под "инструмент пошустрее". тогда 100% за.


RWolf   (2012-03-13 09:39:00) [15]

ну так, может, использовать инструмент пошустрее?
у меня вот в аналогичной задаче используется сервер БД Firebird с его системой оповещений, работает весьма быстро, задержками можно пренебречь.


sniknik   (2012-03-13 09:31:00) [16]

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

удачи.

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

и не получится. но все одно, удачи еще раз. она тебе понадобится.


Alex_C   (2012-03-13 09:14:00) [17]


> при чем тут синхронайзы и т.п...


Меня опять не поняли :)
Я и заношу, где парсю. Но по условиям задачи я МГНОВЕННО должен отобразить занесенный в базу спот!
А это у меня не получается, т.к. при использовании отдельного ADOConnect в отдельном треде, в другом ADOConnect+ADODataSet+DBGrid увидеть внесенные данные я смогу только через 5 сек - это отражено у Майкрософта.
Вот сейчас и пытаюсь обойти это правило 5 сек.
Вроде как у майкрософта это нужно обходить как написано в [46] - но пока это у меня не получилось.


Inovet   (2012-03-12 20:44:00) [18]

> [46] Alex_C   (12.03.12 14:40)
> Вот первая часть моей задачи.

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


знайка   (2012-03-12 20:35:00) [19]


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

И напрашивается тут вин-сервис для синхронизации с инетом, раз уж эти споты постоянно идут.


Inovet   (2012-03-12 20:15:00) [20]

> [40] Alex_C   (12.03.12 09:33)
> Раньше я его динамически расчитывал при отрисовке таблицы.

Скорее всего надо расчитывать раньше отрисовки таблицы и выводить при отрисовке. В твоём случае отрисовка в гуе и получение новых данных из Инеета не связаны. А уж в базе результаты расчёта совсем не нужны, если мстория нужна - храни исходные скачанные с меткой времени, они более информативны, и можешь восстановить в любое время Индекс Нужности на заданный момент, ну если требуется такое.


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

Наверх

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