我正在使用Delphi XE6和UniDAC以及MySQL
我的DM中有一些TUniQuery组件,我想重复刷新主题,所以我在主窗体中放了一些Timers,在每个定时器中创建一个线程并将查询传递给它以刷新数据:
例如:
TUpdateThread = class(TThread)
private
FQuery : TUniQuery;
FResultHandle : THandle;
public
constructor Create(var Query : TUniQuery; ResultHandle : THandle);
protected
procedure Execute; override;
end;
constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
inherited Create;
Suspend;
FQuery := Query;
FResultHandle := ResultHandle;
FreeOnTerminate := True;
Resume;
end;
procedure TUpdateThread.Execute;
var
Msg : String;
B : Boolean;
begin
try
B := True;
try
FQuery.Refresh;
except
on E:Exception do
begin
B := False;
Msg := 'Error : ' + #13 + E.Message;
SendMessage(FResultHandle, MSG_UPDATERESULT, 2, Integer(Msg));
end;
end;
finally
if B = True then
SendMessage(FResultHandle, MSG_UPDATERESULT, 1, 1);
Terminate;
end;
end;
有时它成功完成但很多次我遇到了一些错误,例如AV或“Net Pack Header ...”错误 或者有时候我的网格(Ehlib DBGrid)有问题,例如绘图行中的错误或...(特别是当我使用DisableControls和EnableControls时) 所有查询都有相同的连接,我认为每个Thread应该有自己的连接,因为所有的定时器间隔都相同,我建议有时刷新查询会中断对方
事实上,我的数据库位于VPS服务器中,并且有一些客户端应用程序,我希望在客户端中安装Live-Tables并重复更新主题
实现这一目标的最佳方法是什么? 如何在没有应用程序挂起的情况下更新我的表格! 有一些组件作为TThreadTimer(或......),主题对这种情况有用吗?!
谢谢......
答案 0 :(得分:1)
第一个问题在这里:
constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle);
begin
inherited Create; // Create with no arguments
Suspend; // means CreateSuspended = false
FQuery := Query;
FResultHandle := ResultHandle;
FreeOnTerminate := True;
Resume;
end;
在这里,您使用默认构造函数(CreateSuspended = false
)创建线程,其中线程立即开始运行。您可以立即调用suspend
(已弃用且不应使用),但这仍然是竞争条件,因为您的线程在分配之前可能会或可能不会开始尝试Refresh
您的查询。要在挂起状态下创建线程,请使用
inherited Create(true);
Resume
也已弃用。相反,您应该使用Start;
。
此外,您将TUniQuery
传递给此线程的构造函数。我想,我认为这个查询与主线程具有亲和性 - 这就是说它(可能)是表单上的可视化组件,具有与可视组件的数据绑定,或者由用户或用户以其他方式与之交互接口。
如果是这样的答案,那就是你根本无法做到这一点 - 一个线程无法修改与另一个线程具有亲缘关系的对象。例如,当后台线程同时销毁它们以准备刷新查询内容时,您的界面可能正在从查询中检索记录。当然这会引起各种各样的问题。
简单的解决方案是使用常规计时器并在主线程上同步刷新。如果这需要太长时间,那么您需要完全考虑不同的策略。我们真的没有足够的信息来进一步提出建议。如果网络访问和I / O是瓶颈,那么您可以考虑异步刷新到该线程拥有的单独查询对象,然后将其同步分配给您的视图组件。