为何仅含DECIMAL/NUMERIC类型的MSSQL表会触发ODBC连接忙错误?
解决FireDAC打开含DECIMAL类型MSSQL表时的"Connection is busy with results for another hstmt"错误
问题背景
当你使用FireDAC的TFDTable连接MSSQL数据库,且FetchOptions.Items包含fiMeta时,打开带有DECIMAL/NUMERIC类型字段的表会触发错误:
Connection is busy with results for another hstmt
为什么只有DECIMAL字段会触发这个问题?
这个情况和FireDAC获取元数据的特殊逻辑直接相关:
- 对于大多数数据类型(比如INT、VARCHAR),FireDAC可以通过单次ODBC调用获取完整的字段元数据;
- 但DECIMAL/NUMERIC类型需要额外的ODBC调用(比如
SQLColAttribute来获取精度和刻度信息),而当fiMeta启用时,FireDAC会在打开主数据集的同时并行发起元数据查询; - MSSQL的ODBC驱动默认不允许同一个连接上同时存在多个未完成的语句句柄(hstmt),此时主数据集的hstmt还处于活跃状态,元数据查询的hstmt就会触发冲突,抛出上述错误。
可行的解决方案
这里有几个针对性的解决办法,你可以根据自己的场景选择:
启用MARS(多活动结果集)
在FireDAC的连接字符串中添加MARS_Connection=Yes,这样MSSQL ODBC驱动允许同一个连接同时处理多个活跃的hstmt,从根源上解决冲突。
示例连接配置:FDConnection1.Params.Add('DriverID=MSSQL'); FDConnection1.Params.Add('Server=your_server'); FDConnection1.Params.Add('Database=your_db'); FDConnection1.Params.Add('User_Name=your_user'); FDConnection1.Params.Add('Password=your_pass'); FDConnection1.Params.Add('MARS_Connection=Yes'); // 关键配置移除fiMeta选项
如果你的业务不需要提前获取元数据(比如不需要在打开表前就知道字段属性),可以从FetchOptions.Items中移除fiMeta。这样FireDAC会在数据加载完成后再获取元数据,避免并行的hstmt操作:FDTable1.FetchOptions.Items := FDTable1.FetchOptions.Items - [fiMeta];手动预取元数据
在打开表之前,手动调用GetMetadata方法提前获取并关闭元数据查询的hstmt,再打开主数据集:FDTable1.GetMetadata; // 预取元数据,此时元数据查询的hstmt会被关闭 FDTable1.Open;配置独立的元数据连接
在FireDAC的全局配置或连接配置中,设置使用单独的连接来处理元数据查询,让主连接和元数据连接相互隔离:FDManager1.ConnectionDefs.AddConnectionDef('MetaConn', 'MSSQL', 'your_connection_string'); FDTable1.MetaDataConnection := FDConnection2; // 指向单独的元数据连接
内容的提问来源于stack exchange,提问作者Jan Doggen
相关产品推荐
相关产品推荐

