Форум: "Базы";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];
ВнизКоннект к базе в дополнительном потоке Найти похожие ветки
← →
Piter © (2005-08-29 23:50) [0]Вот думаю - как правильно реализовать соединение с базой в отдельном потоке.
Допустим, есть класс от TThread... Но как им управлять?
Хочется реализовать так, чтобы ему можно было дать любое SQL выражение, он его выполнит. Ну если с INSERT, UPDATE понятно... То что делать с SELECT? Как поток вернет набор данных?
← →
Reindeer Moss Eater © (2005-08-30 00:18) [1]Вернет.
А куда он денется с подводной-то лодки?
← →
Alexander Panov © (2005-08-30 00:30) [2]Piter © (29.08.05 23:50)
Схематично:TQueryComplete=procedure(Query: TQuery) of object;
TQueryThread=class(Tthread)
private
FDB: TDatabase;
FQuery: TQuery;
FStr: String;
FOnComplete: TQueryComplete;
protected
procedure Execute; override;
public
procedure ExecQuery(const Query: String);
property OnComplete: TQueryComplete read FOnComplete write FOnComplete;
end;
procedure TQueryThread.Execute;
begin
FDB := TDatabase.CReate(nil);
...
FQuery := TQuery.CReate;
...
Suspend;
while not Terminated do
begin
try
FQuery.Close;
FQUery.Sql.Text := FStr;
if UpperCase(Copy(FStr,1,6))="SELECT"
then FQuery.Open
else FQuery.ExecSql;
except
end;
if Assigned(FOnComplete) then FOnComplete(FQuery);
Suspend;
end;
end;
procedure TQueryThread.ExecQuery(const Query: String);
begin
FStr := Query;
Resume;
end;
Примерно так можно.
← →
Reindeer Moss Eater © (2005-08-30 00:35) [3]Вообще TDataSet является threadsafe классом.
Надо лишь визуальные контролы подключать к нему после открытия.
← →
Piter © (2005-08-30 01:42) [4]Ну вот допустим такой вопрос...
Связь с базой данных медленная - плохой канал связи там или например операция с базой выполняется длительное время.
Соответственно какой-нибудь оператор Query.ExecSQL может повесить приложение на несколько минут, интерфейс недоступен - нехорошо.
Выход - работать с базой в потоке, ок.
Но возникает вопрос - а как "нормально" прервать данный процесс? Например, если приложение надо срочно закрыть?
Если сделали Query.ExeSQL и идет работа - думаю, некорректно будет из другого потока делать Query.Free? А что же тогда делать? Какая-то безвыходная ситуация...
Или вот способо прервать - это сделать TDatabase.Connect := false... но опять же - когда идет работа - разве корректно будет из другого потока делать Database.Connect := false?
← →
Карелин Артем © (2005-08-30 06:03) [5]Если очень надо - уничтожай поток. Некоторые товарищи писали что это неправильно, однако аргументов по этому поводу не предоставляли. :)
← →
Alexander Panov © (2005-08-30 08:52) [6]Piter © (30.08.05 1:42) [4]
Free для доп. потока теюе не поможет, как и Database.Close.
Только TerminateThread.
← →
Piter © (2005-08-30 13:22) [7]То есть, нормального способа прервать длительную операцию нет?
Блин... неправильно это как-то... нелогично. Неужели не предусмотрели...
← →
Val © (2005-08-30 13:30) [8]...однако аргументов по этому поводу не предоставляли...
Аргумент стандартен: Что SQL сервер знает о клиентских потоках?
← →
Alexander Panov © (2005-08-30 13:38) [9]Val © (30.08.05 13:30) [8]
Что SQL сервер знает о клиентских потоках?
А ему оно надо?
← →
Val © (2005-08-30 13:42) [10]не думаю. поэтому он спокойно колбасит себе свои запросы и далее.
← →
ANB © (2005-08-30 14:04) [11]Для асинхронки выход один (имхо) - уходить на специфичные для нужного сервера методы доступа. Для Oracle и MS SQL поддерживается асинхронка. Вывод длительных запросов в отдельный поток решает только проблему неподвисания интерфейса, но снять такой запрос будет проблематично. В ADO есть возможность организовать асинхронное выполнение без отдельных потоков, но, во первых, работает не всегда, во вторых - я все равно не нашел, как прервать такую операцию.
← →
Anatoly Podgoretsky © (2005-08-30 14:17) [12]Alexander Panov © (30.08.05 13:38) [9]
Хотелось бы, что бы от этого сервер не вставал колом, когда пьяный программист вдруг возьмем и грохнет все. Случаи известны.
← →
ANB © (2005-08-30 14:21) [13]
> Anatoly Podgoretsky © (30.08.05 14:17) [12]
- ну, оракла может стать колом даже при снятии сессии, смотря что в ней гоняли, гы. Тут уже никакая асинхронка не поможет.
← →
isasa © (2005-08-30 15:55) [14]Никто не вспомнил?
{ CoInitFlags determines the COM threading model of the application or current
thread. This bitflag value is passed to CoInitializeEx in ComServ initialization.
Assign COINIT_APARTMENTTHREADED or COINIT_MULTITHREADED to this variable before
Application.Initialize is called by the project source file to select a
threading model. Other CoInitializeEx flags (such as COINIT_SPEED_OVER_MEMORY)
can be OR"d in also. }
var
CoInitFlags: Integer = -1; // defaults to no threading model, call CoInitialize()
← →
Piter © (2005-08-30 16:34) [15]теперь осталось разъяснить, причем здесь COM
← →
isasa © (2005-08-30 16:41) [16]А ComObj используем.
Имеем(по умолчанию) - CoInitialize(),
надо - CoInitializeEx( COINIT_MULTITHREADED ), или хотя бы CoInitializeEx( COINIT_APARTMENTTHREADED )
← →
Piter © (2005-08-30 17:46) [17]isasa © (30.08.05 16:41) [16]
А ComObj используем
не понял. Кто ComObj использует?
Народ!
Вот что придумал. Итак, задаем запрос потоку, он соединяется с базой, выполняет запрос. А потом в Synchronize процедуре возвращает ссылку на Query.Fields - так подойдет?
Если Query создан в доп. потоке, то можно к Query.Fields обращаться в основном потоке для извлечения значения полей?
← →
Карелин Артем © (2005-08-30 19:29) [18]
> Val © (30.08.05 13:42) [10]
Вообще-то он прекращает выполнение запросов в этом случае. По крайней мере в моем софте.
← →
Piter © (2005-08-30 20:12) [19]Piter © (30.08.05 17:46) [17]
Народ!
Вот что придумал. Итак, задаем запрос потоку, он соединяется с базой, выполняет запрос. А потом в Synchronize процедуре возвращает ссылку на Query.Fields - так подойдет?
Отвечаю сам себе - да, подойдет! Видимо, единственный грамотный способ вернуть полученные данные в другой поток
← →
Карелин Артем © (2005-08-30 20:33) [20]
> Piter © (30.08.05 20:12) [19]
А поток как долго будет после этого жить? Может в какой-нибудь набор данных в памяти скапировать данные?
← →
Piter © (2005-08-30 21:02) [21]Карелин Артем © (30.08.05 20:33) [20]
А поток как долго будет после этого жить?
дык потос Syncronize вызывает - соответственно, замрет на это время
Карелин Артем © (30.08.05 20:33) [20]
Может в какой-нибудь набор данных в памяти скапировать данные?
а вот это интересно. Если перекопировать переданный Query.Fields в другой TFields - нормально будет?
← →
Alexander Panov © (2005-08-30 23:45) [22]Piter © (30.08.05 20:12) [19]
Видимо, единственный грамотный способ вернуть полученные данные в другой поток
Хм. видимо мой пример неправильный и TQuery в нем ни в какую нельзя использовать.
← →
Piter © (2005-08-31 00:42) [23]Alexander Panov © (30.08.05 23:45) [22]
твой пример неправильный тем, что вызываешь обработчик событие в доп. потоке, что чревато. Стараются делать VCL совместимое все.
А вот насчет передачи Query через Synchronize тоже чревато - ибо юзер может и Open сделать, и ExecSQL и т.д.
А с TFields особо ничего не сотворишь... пока мне так кажется...
← →
Fay © (2005-08-31 03:43) [24]2 Piter © (29.08.05 23:50)
При фетче легко можно получить что-нибудь типа "Connection is busy"
З.Ы.
Я не дружу с американским 8(
← →
Fay © (2005-08-31 03:44) [25]К Fay © (31.08.05 3:43) [24]
... в случае одного Connection-образного экземпляра для неск. потоков
← →
Карелин Артем © (2005-08-31 05:36) [26]
ClientDataSet1.FieldDefs.Assign(IBQuery1.FieldDefs);
ClientDataSet1.CreateDataSet;
ClientDataSet1.Open;
IBQuery1.First;
while not(IBQuery1.Eof) do
begin
ClientDataSet1.Append;
for i:=0 to IBQuery1.FieldCount-1 do
begin
ClientDataSet1.Fields[i].Value:=IBQuery1.Fields[i].Value;
end;
ClientDataSet1.Post;
IBQuery1.Next;
end;//while
← →
Alexander Panov © (2005-08-31 09:03) [27]Piter © (31.08.05 0:42) [23]
твой пример неправильный тем, что вызываешь обработчик событие в доп. потоке, что чревато. Стараются делать VCL совместимое все.
Пример был не для того, чтобы его использовать напрямую.
Piter © (31.08.05 0:42) [23]
А вот насчет передачи Query через Synchronize тоже чревато - ибо юзер может и Open сделать, и ExecSQL и т.д.
Ты о чем? Какой юзер? Программу пишешь ты а не юзер.
Просмотрел всю ветку сначала, не нашел слова "юзер" ни в одном посте.
← →
Alexander Panov © (2005-08-31 09:04) [28]А про клонирование данных можно забыть.
Ну конечно, если у тебя выборки не могут превышать пары сотен записей, то ради бога.
← →
Piter © (2005-09-18 00:05) [29]А теперь такой вопрос - а если нужно передавать данные SELECT"а в стороннюю DLL (плагин) - то как поступать? То есть, движок базы реализован в самой программн, плагин в виде DLL делает запрос - ок... а как ему вернуть данные?
Надо учесть, что плагин и на C++ может быть написал, и на D, и на чем угодно...
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.036 c