在单独的线程中进行数据库连接 - 最好的方法是什么?

Hol*_*rwa 4 delphi multithreading delphi-2009

我正在创建一个访问数据库的应用程序.在每次访问数据库时,应用程序都会等待作业完成.为了保持UI响应,我想将所有数据库内容放在一个单独的线程中.
这是我的想法:

  • db-thread在创建时创建所需的所有数据库组件
  • 现在线程就坐在那里等待命令
  • 如果它收到命令,它将执行操作并返回空闲状态.在此期间主线程等待.
  • 只要应用程序正在运行,db-thread就会存在

听起来不错吗?
将数据库结果从db-thread导入主线程的最佳方法是什么?
到目前为止,我对线程做的并不多,因此我想知道db-thread是否可以创建一个查询组件,主线程读取结果.主线程和数据库线程永远不会同时访问查询.这还会导致问题吗?

da-*_*oft 6

您正在寻找的是标准数据访问技术,称为异步查询执行.一些数据访问组件以易于使用的方式实现此功能.至少dbGo(ADO)和AnyDAC实现了这一点.让我们考虑一下dbGo.

这个想法很简单 - 你可以调用方便的数据集方法,比如Open.该方法在后台线程中启动所需任务并立即返回.任务完成后,将触发相应的事件,通知应用程序任务已完成.

使用DB GUI应用程序和Open方法的标准方法如下(草稿):

  • 将eoAsyncExecute,eoAsyncFetch,eoAsyncFetchNonBlock包含在数据集ExecuteOptions中;
  • 断开数据集中的TDataSource.DataSet;
  • 将数据集OnFetchComplete设置为proc P;
  • 显示"您好!我们努力处理您的请求.请稍候......"对话框;
  • 调用数据集Open方法;
  • 当查询执行完成时,将调用OnFetchComplete,因此P.和P隐藏"等待"对话框并将TDataSource.DataSet连接回数据集.

此外,您的"等待"对话框可能有一个取消按钮,用户可以使用该按钮取消运行时间过长的查询.


mgh*_*hie 5

首先 - 如果您没有多线程经验,请不要从VCL类开始.使用OmniThreadLibrary,以及(其中包括)这些原因:

  • 您的抽象级别是任务,而不是线程,是处理并发的更好方法.
  • 您可以轻松地在自己的线程中执行任务之间切换,并使用线程池安排它们.
  • 所有低级细节,如线程关闭,双向通信等等都会为您完成.你可以专注于数据库的东西.

db-thread在创建时创建所需的所有数据库组件

这可能不是最好的方法.我通常只在需要时才创建组件,但不会立即销毁.您绝对应该在线程池线程中保持连接打开,并且只有在线程处于非活动状态一段时间后才关闭它,并且池会处理它.但是保留事务和语句对象的缓存通常也是一个好主意.

如果它收到命令,它将执行操作并返回空闲状态.在此期间主线程等待.

第一部分在使用OTL时处理得很好.但是 - 没有主线程等待,这将比首先直接在VCL线程中执行数据库访问带来一点优势.您需要异步设计才能充分利用多个线程.考虑一个标准数据库浏览器表单,它具有过滤记录的控件.每当其中一个控件发生变化时,我会通过(重新)启动计时器来处理这个问题.一旦用户完成编辑定时器事件触发(例如在500毫秒之后),就会启动一个任务,执行根据过滤条件获取数据的语句.网格内容被清除,只有在任务完成后才会重新填充.这可能需要一些时间,因此VCL线程不会等待任务完成.相反,用户甚至可以再次更改过滤条件,在这种情况下,当前任务被取消并且新的任务开始.OTL为您提供完成任务的事件,因此异步设计很容易实现.

将数据库结果从db-thread导入主线程的最佳方法是什么?

我通常不会将数据感知组件用于多线程数据库应用程序,而是使用标准控件作为业务对象的视图.在数据库任务中,我创建这些对象,将它们放入列表中,任务完成事件将列表传输到VCL线程.

主线程和数据库线程永远不会同时访问查询.

对于按需加载数据的所有组件,您无法确定这一点.通常只从db中获取第一个记录,并且在消耗之后继续提取.这些组件显然不能被线程共享.

  • 如果您要采用OTL方式,请务必阅读http://17slon.com/blogs/gabr/2009/02/building-connection-pool.html. (2认同)