每个线程都需要单独的数据库连接.后台线程因此创建数据库连接,创建查询然后执行它.
现在我可以使用后台线程的查询对象访问查询结果.
但是在执行查询之后,我想在主线程中访问查询结果.
如果我只是引用后台线程查询对象,这是否会导致问题,因为我正在访问另一个线程中的数据库连接?
据我所知,在这种情况下,主线程不会有它独立的数据库连接,并使用后台线程中的那个并不好.
我的想法在哪里被扭曲,这是做正确的方法?
解决方法
// create and open query to fetch list of companies while not qryCompanies.Eof do begin C := TCompany.Create; try C.LoadFromDataset(qryCompanies); Companies.Add(C); except C.Free; raise; end; qryCompanies.Next; end;
C是公司的业务对象.它可以由对象(TCompany)或对象实现的接口(ICompany)实现.公司是TList< TCompany>或TList< ICompany>.在任务结束时,您将公司列表发送到VCL线程:
Task.Comm.Send(TOmniMessage.Create(MSGID_LIST_OF_COMPANIES,Companies));
在您要显示公司列表的表单中,您处理正在监视任务的otlEventMonitor实例的OnTaskMessage事件:
procedure TListBaseFrame.otlEventMonitorTaskMessage( const task: IOmniTaskControl); var MsgID: word; MsgValue: TOmniValue; begin task.Comm.Receive(MsgID,MsgValue); Assert(MsgValue.IsInterface); if fLoaderTask = task then begin SetLoadedData(MsgID,MsgValue.AsInterface); // or MsgValue.AsObject); fLoaderTask := nil; end; end;
公司列表取代了以前的列表,可以显示在网格中.
同样,您可以返回单个公司对象/界面进行显示和编辑.
值得思考的两件事:
>如果到目前为止您已经有了接口的首选对象,那么编写多线程程序可能是重新考虑这一点的理由.如果您在后台线程中创建对象,然后将它们传递给VCL线程并在后台线程中忘记它们,那么对象可能会正常工作.然而,我发现通过在应用程序中缓存对象,并且只加载尚未加载或已更改的数据库中的记录,可以获得更好的性能.我的所有表都附加了一个更改索引(64位整数,时间戳也可以工作),每次更新都会更改.而不是执行
select * from foo where (...) order by (...)
我只执行过一次
select id,change_index from foo where (...) order by (...)
然后在高速缓存中检查具有相同id(主键)和更改索引的对象是否已存在,如果是,则返回高速缓存对象,并且仅在不创建新业务对象并加载所有列时.
但是如果你缓存对象,你将从多个线程中引用它们,并且所有权问题很快变得如此复杂,以至于基于引用计数的生命周期管理是保持理智的唯一方法.在这方面使用接口而不是对象有很大帮助.>如果多个线程可以同时访问它们,则必须向每个业务对象添加同步对象.这当然是可能的,但可能会引入额外的复杂性和潜在的死锁.如果将业务对象实现为不可变,则根本不需要锁.我越来越多地使用这种方法,虽然它需要一些习惯,但它可以简化很多事情.