- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当将 TADOQuery
与 [eoAsyncFetchNonBlocking]
结合使用并附加到 OnFetchComplete
事件时,我发现 OnFetchComplete
未执行在主线程中(在XE4和XE8中测试)。我认为这是一个错误*,因为我们大多数人都会在 UI 中处理这些类型的事件。我相信这是大型项目中一些问题的根源,我需要一个解决方法。
[编辑]*阅读 ADO 文档后,我知道这可能不是一个错误,但多线程问题仍然存在。
是否有一种优雅的方法来强制此处理程序中的代码在主线程上执行?我不想使用计时器(但如果这是唯一的解决方案,我会采用它)。或者,是否有一个我可以在这里等待的 ADO 同步对象或向 ADO 提供者发送某种其他形式的信号?
这是一个显示该问题的简化示例。我的项目更加复杂,工厂创建并填充这些数据集,但这里类似于将数据集附加到 ADOQuery1FetchComplete
内的网格。
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls;
type
TForm4 = class(TForm)
Button1: TButton;
Button2: TButton;
ADOQuery1: TADOQuery;
ADOConnection1: TADOConnection;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ADOQuery1FetchComplete(DataSet: TCustomADODataSet;
const Error: Error; var EventStatus: TEventStatus);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FMainThreadID : DWORD;
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.ADOQuery1FetchComplete(DataSet: TCustomADODataSet;
const Error: Error; var EventStatus: TEventStatus);
begin
Assert(FMainThreadID = GetCurrentThreadId); //this assertion fails!
// I need UI code here to run FMainThreadID
end;
procedure TForm4.Button1Click(Sender: TObject);
begin
ADOQuery1.Open;
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
FMainThreadID := GetCurrentThreadId;
end;
end.
dfm 只需使用 ExecuteOptions = [eoAsyncFetchNonBlocking]
和 OnFetchComplete
处理查询集。
object Form4: TForm4
Left = 0
Top = 0
Caption = 'Form4'
ClientHeight = 186
ClientWidth = 258
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 24
Top = 88
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ADOQuery1: TADOQuery
Connection = ADOConnection1
ExecuteOptions = [eoAsyncFetchNonBlocking]
OnFetchComplete = ADOQuery1FetchComplete
Parameters = <>
SQL.Strings = (
'SELECT * FROM TABLENAME')
Left = 144
Top = 16
end
object ADOConnection1: TADOConnection
Connected = True
ConnectionString =
'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +
'fo=False;Initial Catalog=DBNAME;Data Source=.\INSTANCENAME'
LoginPrompt = False
Provider = 'SQLOLEDB.1'
Left = 40
Top = 16
end
end
[编辑]有人建议使用TThread.Sychronize
,但这不是Delphi 线程。
如果GetCurrentThreadId
不足以证明处理程序是从另一个线程调用的,这里是主线程和有问题线程的调用堆栈(为了更好的措施,我在主线程中添加了 sleep )
主线程休眠
:77d0c7bc ntdll.ZwDelayExecution + 0xc
:7745104f KERNELBASE.Sleep + 0xf
Unit6.TForm6.btnQueryClick($32BC00)
Vcl.Controls.TControl.Click
Vcl.StdCtrls.TCustomButton.Click
Vcl.StdCtrls.TCustomButton.CNCommand(???)
Vcl.Controls.TControl.WndProc((48401, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.Controls.TWinControl.WndProc((48401, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.StdCtrls.TButtonControl.WndProc((48401, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.Controls.TControl.Perform(???,???,7275840)
Vcl.Controls.DoControlMsg(???,(no value))
Vcl.Controls.TWinControl.WMCommand((273, (), 1344, 0, (), 7275840, 0))
Vcl.Forms.TCustomForm.WMCommand((273, (), 1344, 0, (), 7275840, 0))
Vcl.Controls.TControl.WndProc((273, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.Controls.TWinControl.WndProc((273, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.Forms.TCustomForm.WndProc((273, 1344, 7275840, 0, 1344, 0, (), 1344, 111, (), 0, 0, ()))
Vcl.Controls.TWinControl.MainWndProc(???)
System.Classes.StdWndProc(2829362,273,1344,7275840)
:759b8e71 user32.CallNextHookEx + 0xb1
:759b90d1 ; C:\windows\SysWOW64\user32.dll
:759b932c ; C:\windows\SysWOW64\user32.dll
:759b9529 ; C:\windows\SysWOW64\user32.dll
:77d107d6 ntdll.KiUserCallbackDispatcher + 0x36
:759be4a9 ; C:\windows\SysWOW64\user32.dll
:711f19e4 ; C:\windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.9600.17810_none_a9edf09f013934e0\comctl32.dll
:711f1a7b ; C:\windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.9600.17810_none_a9edf09f013934e0\comctl32.dll
:759b8e71 user32.CallNextHookEx + 0xb1
:759b90d1 ; C:\windows\SysWOW64\user32.dll
:759bddd5 user32.CallWindowProcW + 0x95
Vcl.Controls.TWinControl.DefaultHandler(???)
:00532947 TWinControl.DefaultHandler + $EB
:00532836 TWinControl.WndProc + $5CA
:00544cdd TButtonControl.WndProc + $71
:004c9162 StdWndProc + $16
:759b8e71 user32.CallNextHookEx + 0xb1
:759b90d1 ; C:\windows\SysWOW64\user32.dll
:759ba66f ; C:\windows\SysWOW64\user32.dll
:759ba6e0 user32.DispatchMessageW + 0x10
:005bb158 TApplication.ProcessMessage + $F8
:00040000
其他线程调用处理程序
Unit6.TForm6.QueryFetchComplete($288B3E0,nil,esOK)
Data.Win.ADODB.TCustomADODataSet.FetchComplete(nil,89849068,Pointer($3299D8) as _Recordset)
:6b7ab81d ; C:\Program Files (x86)\Common Files\System\ado\msado15.dll
:6b7ab4b6 ; C:\Program Files (x86)\Common Files\System\ado\msado15.dll
:6b7a17c8 ; C:\Program Files (x86)\Common Files\System\ado\msado15.dll
:6b7b616f ; C:\Program Files (x86)\Common Files\System\ado\msado15.dll
:69038991 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:69038bd6 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:69038d54 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:69037a02 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:69021205 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:69038034 ; C:\Program Files (x86)\Common Files\System\msadc\msadce.dll
:77a07c04 KERNEL32.BaseThreadInitThunk + 0x24
:77d2ad1f ntdll.RtlInitializeExceptionChain + 0x8f
:77d2acea ntdll.RtlInitializeExceptionChain + 0x5a
最佳答案
根据我的经验,更简单的方法是使用:
这不是一个错误,或者至少不是一个 VCL 错误。此行为由提供商处理,我们不能说它不遵循 specification因为没有关于如何管理这些事件的异步性的规范。所有规范如下:
adAsyncFetchNonBlocking
Indicates that the main thread never blocks while retrieving. If the requested row has not been retrieved, the current row automatically moves to the end of the file.
这是警告主线程执行已完成的代码示例:
procedure TForm1.ADOQuery1FetchComplete(DataSet: TCustomADODataSet;
const Error: Error; var EventStatus: TEventStatus);
begin
TThread.Synchronize(nil,
procedure
begin
ShowMessage('FetchData Completed');
end
);
end;
更新:
我确认了这一点。它适用于版本 6、7、XE4 和 XE7(我这里没有其他版本)。使用 Synchronize
注入(inject)代码以在主线程上下文中执行并没有什么问题。另外,我想让您注意这样一个事实:DataSet 只是指向 ADOQuery 对象的指针(实际上是引用),因此您不必在匿名方法上引用它,这对于旧版本来说是一个重要事实像 6 或 7,因为匿名方法不存在。
关于delphi - 异步 TADOQuery 的 OnFetchComplete 未同步到主线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30900730/
使用 Delphi 2010 谁能告诉我我的代码做错了什么。注释显示了我使用尝试将参数传递给 ADOQuery 的特定方法时收到的错误 procedure CreateAdminLogin(const
我对 TADOQuery 的行为感到困惑,我们就打Q .当我使用 Q.Edit ,填充一些字段,然后 Post ,它最终实际上插入了一条新记录。 代码很简单,从对象中读取ID: Q.SQL.Text
Delphi TAdoQuery 是否可以一次性执行多个插入,或者是否必须单独执行每个语句?我想做的是这样的: AdoQuery.SQL.Clear; AdoQuery.SQL.Add('INSERT
快速提问(希望如此) 我有一个大型数据集(>100,000 条记录),我想将其用作查找以确定多个键是否存在。这样做的目的是在尝试将 FK 违规提交到数据库之前找到它们,以避免由此产生的 EDataba
我正在使用 Delphi 5 和 ADO 开发一个小型糖尿病程序。我做了一个像这样的小查询: function GetLowestGlucoseLevel(StartDate:string;EndDa
这个问题已经有答案了: 已关闭12 年前。 Possible Duplicate: How to run a database script file from Delphi? 我有一个非常长的 SQ
我在 TADOQuery 方面遇到了一个大问题: 这是我的 SQL: select cast(-10 as number(9)) foo, -10 bar from dual 当您添加“foo”字
我有一个简单的基本问题,我尝试使用 Insert 语句将图像插入数据库,其他列值也使用 TADOQuery 组件。 由于代码已经由某人编写,因此我想在此处放置一些虚拟示例代码,以供您澄清相应的步骤。
我使用此代码将行从 Table1 复制到 Table2,但它给了我 Command Text does not return a result set ADOQuery1.Close; ADOQu
我试图只选择顶部 否 TADOQuery 中的项目,但是当我激活查询时它给了我和错误。似乎找到了top参数就好了,但是执行的时候没能替换掉。如果我不使用“Top N”限制 SQL 语句,则代码可以正常
我通常使用带有持久字段的 TADOQuery(每个表 1 个),但现在我发现自己陷入了困境:我必须同时运行多个查询(只读)。 我发现了很多关于线程的文档。然而,这意味着每个操作都有一个新创建的 TAD
我有一个 TADOQuery,如果我硬编码“Where 参数”,它会生成一个临时表,它工作正常,但如果我使用 TADO 参数,则下一个查询不知道临时表。 我做错了什么? 我希望我可以简化这个例子,但它
假设我们有一个带有两个 TADOQuery 的标准主从关系。当在主数据集上进行导航时,详细数据集不会出现 AfterOpen 事件。 此事件在其他数据访问包(例如 BDE)中出现。为什么 dbGo 的
我有一个复杂的查询,其中包含多个必须替换相同主键值的位置。它看起来像这样: select Foo.Id, Foo.BearBaitId, Foo.LinkType,
我们使用具有显式连接的 Delphi TADOQuery 进行插入。 摘要:如果在查询处于 dsInsert 状态时连接丢失,查询似乎会进入与基础 ADO 记录集不一致的状态。因此,即使连接已重新建立
我在返回使用 TADOQuery 从简单 SELECT 查询获取的值时遇到问题 下面是我的代码: dbWizconQuery.SQL.Clear; dbWizconQuery.SQL.Add(
我有一个 Delphi 7 项目,我使用 TAdoQuery.ParseSql(); 来加载参数。现在我在XE4中编译它,参数类型有时是错误的。它实际上是 ftInteger,但创建为 ftSmall
使用单个TADOQuery,我使用左外连接从两个不同的表中提取记录: Select M*, D.* from Courier M Left outer join Courier_VT D on M.C
当将 TADOQuery 与 [eoAsyncFetchNonBlocking] 结合使用并附加到 OnFetchComplete 事件时,我发现 OnFetchComplete 未执行在主线程中(在
概述: 我编写了一个应用程序,允许用户定义查询,将其提交到服务器并查看结果。该软件可以在 DB2 或 MySQL 上运行。 问题: 我们在 DB2 版本中遇到了用户尝试运行查询的问题,但发现它失败了,
我是一名优秀的程序员,十分优秀!