使用 DECIMAL 类型打开 MSSQL TFDTable:'Connection is busy with results for another hstmt' when FetchOptions.Items contains fiMeta
Opening MSSQL TFDTable with DECIMAL types: 'Connection is busy with results for another hstmt' when FetchOptions.Items contains fiMeta
如果我打开包含 DECIMAL/NUMERIC 数据类型的 MSSQL table,我会收到 'Connection is busy with results for another hstmt' 错误。
跟踪 FireDAC 代码,我看到它在获取元信息时发生了这种情况,请参阅堆栈跟踪:
我知道错误是关于 multiple open connections to the ODBC database,可能是因为数据集没有一次检索所有数据(并保持打开状态),但我所做的 不是 理解是:
- 为什么只有 table 包含 DECIMAL 字段时才会发生这种情况?其他 table 工作得很好,无论大小,我可以同时在多个选项卡上打开许多网格,甚至可以编辑数据。
- 为什么元数据相关?如果我这样做
FetchOptions.Items := FetchOptions.Items - [fiMeta];
不会发生错误。这是 FireDAC 中的错误吗?
我们在 TFDConnection
上明确设置了 FetchOptions.Mode := fmAll
(作为唯一的提取选项)并且没有覆盖 TFDTable
中的选项。
这是一个小型测试应用程序,我(目前)对代码中的 [fiMeta]
排除不满意 table:我现在必须重新测试我们的主要应用程序因为这个排斥而摔倒。
还有其他方法可以解决这个问题吗?
在我的 TFDConnection
中启用 MARS 会有帮助吗?我该怎么做?
我已经使用 TFDMoniFlatFileClientLink
来检查有关 MARS 的情况。我的代码是否使用运行时赋值 TFDConnection.DriverName := 'MSSQL'
、 或 我在设计时设置了 DriverName(然后 Params.MARS
出现并被选中),这就是我所看到的在跟踪中:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test"]
如果我明确添加 Params.Add('MARS=No');
这将更改为:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test;MARS_Connection=No"]
...这让我想知道 MARS 是否处于活动状态。
如果我明确添加 Params.Add('MARS=Yes');
这将更改为:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test;MARS_Connection=Yes"]
...但问题并没有消失。
背景资料:
- 根据 Browsing Tables (FireDAC) 我们在实时数据 Window 模式下操作,因为
CachedUpdates
、FetchOptions.UniDirectional
和 FetchOptions.CursorKind
有它们的默认值
- Delphi东京 10.2.3,Win 32 应用程序
- 必须支持 SQL Server 2005 及更高版本
- 无论是否使用
dtBCD
和 dtFmtBCD
字段类型的映射规则都会发生这种情况
- 有一个 Embarcadero forums thread 关于这个。
- DelphiPraxis post here,无解
测试table:
CREATE TABLE dbo.TESTDEC
(
TT_ID INTEGER NOT NULL CONSTRAINT TT_C0_TEST DEFAULT 0,
TT_DEC DECIMAL NULL,
TT_NUM NUMERIC NULL,
TT_DEC5_0 DECIMAL(5,0) NULL,
TT_NUM5_0 NUMERIC(5,0) NULL,
TT_DEC5_3 DECIMAL(5,3) NULL,
TT_NUM5_3 NUMERIC(5,3) NULL,
TT_DEC15_0 DECIMAL(15,0) NULL,
TT_NUM15_0 NUMERIC(15,0) NULL,
TT_DEC15_3 DECIMAL(15,3) NULL,
TT_NUM15_3 NUMERIC(15,3) NULL,
TT_DEC25_0 DECIMAL(25,0) NULL,
TT_NUM25_0 NUMERIC(25,0) NULL,
TT_DEC25_3 DECIMAL(25,3) NULL,
TT_NUM25_3 NUMERIC(25,3) NULL,
TT_DEC35_0 DECIMAL(35,0) NULL,
TT_NUM35_0 NUMERIC(35,0) NULL,
TT_DEC35_3 DECIMAL(35,3) NULL,
TT_NUM35_3 NUMERIC(35,3) NULL
);
insert into dbo.testdec values(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
insert into dbo.testdec values(2,2,2,2,2,2.22,2.22,2,2,2.22,2.22,2,2,2.22,2.22,2,2,2.22,2.22);
insert into dbo.testdec values(3,33333,33333,33333,33333,33.333,33.333,33333333333,33333333333,33333333333.333,33333333333.333,33333333333,33333333333,33333333333.333,33333333333.333,33333333333,33333333333,33333333333.333,2.22);
完整示例程序源
如果需要,将 FDConnection.Params.Add('MARS=Yes');
或 FDConnection.FetchOptions.Mode := fmAll;
添加到 FormShow;他们没有区别。
.dpr 文件:
program BrowseSQLDecimal;
uses
Forms,
uTest in 'uTest.pas' {FrmTest};
{$R *.res}
begin
Application.Initialize;
Application.Title := 'Browse DB';
Application.CreateForm(TFrmTest, FrmTest);
Application.Run;
end.
表格.pas:
unit uTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Vcl.StdCtrls,
FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MSSQL,
FireDAC.Phys.MSSQLDef, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS,
FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Comp.DataSet,
FireDAC.Comp.Client, FireDAC.Moni.Base, FireDAC.Moni.FlatFile;
type
TFrmTest = class(TForm)
Button1: TButton;
Button2: TButton;
FDConnection: TFDConnection;
TableTT_ACT: TFDTable;
TableTESTDEC: TFDTable;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;
var
FrmTest: TFrmTest;
implementation
{$R *.dfm}
procedure TFrmTest.Button1Click(Sender: TObject);
begin
TableTT_ACT.TableName := 'TT_ACT';
TableTT_ACT.Open;
end;
procedure TFrmTest.Button2Click(Sender: TObject);
begin
TableTESTDEC.TableName := 'TESTDEC';
TableTESTDEC.Open;
end;
procedure TFrmTest.FormShow(Sender: TObject);
begin
FDConnection.Open;
end;
end.
表格.dfm:
object FrmTest: TFrmTest
Left = 0
Top = 0
Caption = 'Test'
ClientHeight = 276
ClientWidth = 560
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 32
Top = 24
Width = 97
Height = 25
Caption = 'Open TT_ACT'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 32
Top = 56
Width = 97
Height = 25
Caption = 'Open TESTDEC'
TabOrder = 1
OnClick = Button2Click
end
object FDConnection: TFDConnection
Params.Strings = (
'MonitorBy=FlatFile'
'DriverID=MSSQL'
'User_Name=test'
'Password=test'
'Database=test'
'Server=VS2003-2008')
Left = 224
Top = 24
end
object TableTT_ACT: TFDTable
Connection = FDConnection
Left = 72
Top = 149
end
object TableTESTDEC: TFDTable
Connection = FDConnection
Left = 72
Top = 213
end
end
这是驱动程序问题。
我的 Windows 7 开发机器 只有 有(默认?)32 位 ODBC 驱动程序,名为 SQL Server,版本 6.01.7601.17514
如果我安装更高版本的本机客户端或 ODBC 驱动程序,则没有问题。
另一种解决方法(如问题中所述)是为 TFDTable
更改 FetchOptions.Items := FetchOptions.Items - [fiMeta];
(不要为 TFDConnection
更改,其他数据库不需要这样做使用该连接的组件)。
备注:
测试:
这不适用于 Microsoft ODBC Driver 17 for SQL Server,因为 FireDAC 代码尚未检测到该驱动程序。 TFDPhysODBCDriverBase.FindBestDriver
对驱动程序的名称进行字符串比较,代码中的最新硬连线 SQL 服务器驱动程序字符串是 ODBC DRIVER 13 FOR SQL SERVER和 SQL 服务器本机客户端 11.0. 1,2
使用这些下载的 x64 版本;他们将(也)安装 32 位 ODBC 驱动程序。
这是关于驱动机器上安装的运行程序,即不管数据库服务器上安装了什么。
我还有一个问题:这实际上不是一个 FireDAC 错误吗?为什么 FireDAC 代码执行 TFDPhysCommandAsyncOpen
(参见有问题的堆栈转储)而不是同步执行?
1. SQL Server Native Client 9 也不是
出席
2. Request done
如果我打开包含 DECIMAL/NUMERIC 数据类型的 MSSQL table,我会收到 'Connection is busy with results for another hstmt' 错误。 跟踪 FireDAC 代码,我看到它在获取元信息时发生了这种情况,请参阅堆栈跟踪:
我知道错误是关于 multiple open connections to the ODBC database,可能是因为数据集没有一次检索所有数据(并保持打开状态),但我所做的 不是 理解是:
- 为什么只有 table 包含 DECIMAL 字段时才会发生这种情况?其他 table 工作得很好,无论大小,我可以同时在多个选项卡上打开许多网格,甚至可以编辑数据。
- 为什么元数据相关?如果我这样做
FetchOptions.Items := FetchOptions.Items - [fiMeta];
不会发生错误。这是 FireDAC 中的错误吗?
我们在 TFDConnection
上明确设置了 FetchOptions.Mode := fmAll
(作为唯一的提取选项)并且没有覆盖 TFDTable
中的选项。
这是一个小型测试应用程序,我(目前)对代码中的 [fiMeta]
排除不满意 table:我现在必须重新测试我们的主要应用程序因为这个排斥而摔倒。
还有其他方法可以解决这个问题吗?
在我的 TFDConnection
中启用 MARS 会有帮助吗?我该怎么做?
我已经使用 TFDMoniFlatFileClientLink
来检查有关 MARS 的情况。我的代码是否使用运行时赋值 TFDConnection.DriverName := 'MSSQL'
、 或 我在设计时设置了 DriverName(然后 Params.MARS
出现并被选中),这就是我所看到的在跟踪中:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test"]
如果我明确添加 Params.Add('MARS=No');
这将更改为:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test;MARS_Connection=No"]
...这让我想知道 MARS 是否处于活动状态。
如果我明确添加 Params.Add('MARS=Yes');
这将更改为:
SQLDriverConnect [szConnStr="DRIVER=SQL Server;UID=test;PWD=****;Server=VS2003-2008;Database=test;MARS_Connection=Yes"]
...但问题并没有消失。
背景资料:
- 根据 Browsing Tables (FireDAC) 我们在实时数据 Window 模式下操作,因为
CachedUpdates
、FetchOptions.UniDirectional
和FetchOptions.CursorKind
有它们的默认值 - Delphi东京 10.2.3,Win 32 应用程序
- 必须支持 SQL Server 2005 及更高版本
- 无论是否使用
dtBCD
和dtFmtBCD
字段类型的映射规则都会发生这种情况 - 有一个 Embarcadero forums thread 关于这个。
- DelphiPraxis post here,无解
测试table:
CREATE TABLE dbo.TESTDEC
(
TT_ID INTEGER NOT NULL CONSTRAINT TT_C0_TEST DEFAULT 0,
TT_DEC DECIMAL NULL,
TT_NUM NUMERIC NULL,
TT_DEC5_0 DECIMAL(5,0) NULL,
TT_NUM5_0 NUMERIC(5,0) NULL,
TT_DEC5_3 DECIMAL(5,3) NULL,
TT_NUM5_3 NUMERIC(5,3) NULL,
TT_DEC15_0 DECIMAL(15,0) NULL,
TT_NUM15_0 NUMERIC(15,0) NULL,
TT_DEC15_3 DECIMAL(15,3) NULL,
TT_NUM15_3 NUMERIC(15,3) NULL,
TT_DEC25_0 DECIMAL(25,0) NULL,
TT_NUM25_0 NUMERIC(25,0) NULL,
TT_DEC25_3 DECIMAL(25,3) NULL,
TT_NUM25_3 NUMERIC(25,3) NULL,
TT_DEC35_0 DECIMAL(35,0) NULL,
TT_NUM35_0 NUMERIC(35,0) NULL,
TT_DEC35_3 DECIMAL(35,3) NULL,
TT_NUM35_3 NUMERIC(35,3) NULL
);
insert into dbo.testdec values(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
insert into dbo.testdec values(2,2,2,2,2,2.22,2.22,2,2,2.22,2.22,2,2,2.22,2.22,2,2,2.22,2.22);
insert into dbo.testdec values(3,33333,33333,33333,33333,33.333,33.333,33333333333,33333333333,33333333333.333,33333333333.333,33333333333,33333333333,33333333333.333,33333333333.333,33333333333,33333333333,33333333333.333,2.22);
完整示例程序源
如果需要,将 FDConnection.Params.Add('MARS=Yes');
或 FDConnection.FetchOptions.Mode := fmAll;
添加到 FormShow;他们没有区别。
.dpr 文件:
program BrowseSQLDecimal;
uses
Forms,
uTest in 'uTest.pas' {FrmTest};
{$R *.res}
begin
Application.Initialize;
Application.Title := 'Browse DB';
Application.CreateForm(TFrmTest, FrmTest);
Application.Run;
end.
表格.pas:
unit uTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Vcl.StdCtrls,
FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MSSQL,
FireDAC.Phys.MSSQLDef, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS,
FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Comp.DataSet,
FireDAC.Comp.Client, FireDAC.Moni.Base, FireDAC.Moni.FlatFile;
type
TFrmTest = class(TForm)
Button1: TButton;
Button2: TButton;
FDConnection: TFDConnection;
TableTT_ACT: TFDTable;
TableTESTDEC: TFDTable;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;
var
FrmTest: TFrmTest;
implementation
{$R *.dfm}
procedure TFrmTest.Button1Click(Sender: TObject);
begin
TableTT_ACT.TableName := 'TT_ACT';
TableTT_ACT.Open;
end;
procedure TFrmTest.Button2Click(Sender: TObject);
begin
TableTESTDEC.TableName := 'TESTDEC';
TableTESTDEC.Open;
end;
procedure TFrmTest.FormShow(Sender: TObject);
begin
FDConnection.Open;
end;
end.
表格.dfm:
object FrmTest: TFrmTest
Left = 0
Top = 0
Caption = 'Test'
ClientHeight = 276
ClientWidth = 560
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 32
Top = 24
Width = 97
Height = 25
Caption = 'Open TT_ACT'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 32
Top = 56
Width = 97
Height = 25
Caption = 'Open TESTDEC'
TabOrder = 1
OnClick = Button2Click
end
object FDConnection: TFDConnection
Params.Strings = (
'MonitorBy=FlatFile'
'DriverID=MSSQL'
'User_Name=test'
'Password=test'
'Database=test'
'Server=VS2003-2008')
Left = 224
Top = 24
end
object TableTT_ACT: TFDTable
Connection = FDConnection
Left = 72
Top = 149
end
object TableTESTDEC: TFDTable
Connection = FDConnection
Left = 72
Top = 213
end
end
这是驱动程序问题。
我的 Windows 7 开发机器 只有 有(默认?)32 位 ODBC 驱动程序,名为 SQL Server,版本 6.01.7601.17514
如果我安装更高版本的本机客户端或 ODBC 驱动程序,则没有问题。
另一种解决方法(如问题中所述)是为 TFDTable
更改 FetchOptions.Items := FetchOptions.Items - [fiMeta];
(不要为 TFDConnection
更改,其他数据库不需要这样做使用该连接的组件)。
备注:
测试:
这不适用于 Microsoft ODBC Driver 17 for SQL Server,因为 FireDAC 代码尚未检测到该驱动程序。
TFDPhysODBCDriverBase.FindBestDriver
对驱动程序的名称进行字符串比较,代码中的最新硬连线 SQL 服务器驱动程序字符串是 ODBC DRIVER 13 FOR SQL SERVER和 SQL 服务器本机客户端 11.0. 1,2使用这些下载的 x64 版本;他们将(也)安装 32 位 ODBC 驱动程序。
这是关于驱动机器上安装的运行程序,即不管数据库服务器上安装了什么。
我还有一个问题:这实际上不是一个 FireDAC 错误吗?为什么 FireDAC 代码执行
TFDPhysCommandAsyncOpen
(参见有问题的堆栈转储)而不是同步执行?
1. SQL Server Native Client 9 也不是
出席
2. Request done