阵列DML(FireDAC)

来自RAD Studio
跳转到:航行,搜索

转到使用命令(FireDAC)

概述

Array DML执行技术提交一个带有参数数组的DBMS命令。每个命令参数都有一个值数组,所有参数都有相同长度的数组。然后,FireDAC请求DBMS对数组中的每一行执行一次命令。此技术减少了DBMS和客户端之间的通信量,使DBMS能够流式执行命令,并加快了执行时间。

下图说明了此过程:

FDPhysCmdBatch.png文件

在FireDAC术语中,“批处理命令执行”和“数组DML执行”通常用作同义词。数组DML可以用于几乎所有参数化命令,包括存储过程调用。FireDAC使用本机DBMS API功能实现阵列DML,如果DBMS API不支持,则模拟阵列DML执行。

下表列出了DBMS和阵列DML功能:

数据库管理系统 阵列DML实现 阵列DML模式 阵列DML限制症状
Advantage数据库 仿真 aeUpToFirst错误
数据快照服务器 仿真 aeUpToFirst错误
IBM DB2 本地 aeCollectAllErrors(收集所有错误)
Informix公司 本地 aeCollectAll错误
InterBase v<XE3 仿真 aeUpToFirst错误
InterBase v>=XE3 本机(命令批处理API) aeUpToFirst错误
Firebird v<2.1 仿真 aeUpToFirst错误
Firebird v>=2.1 本机(执行块) aeOnErrorUndoAll(错误全部取消) “上下文太多”错误
Microsoft SQL Server 本地 aeCollectAllErrors(收集所有错误) 可能的“访问冲突”错误
Microsoft Access数据库 仿真 aeUpToFirst错误
MySQL服务器 本机(带多个值的INSERT) aeOnErrorUndoAll(错误全部取消)
数据库服务器 本机(OCI阵列DML) aeUpToFirst错误 应用程序挂起。显式限制-65K个数组项。
PostgreSQL v<8.1 仿真 aeUpToFirst错误
PostgreSQL v>=8.1 本机(带多个值的INSERT/MERGE) aeOnErrorUndoAll(错误全部取消)
SQLite数据库v<3.7.11 仿真 aeUpToFirst错误
SQLite数据库v>=3.7.11
  • 仿真,当参数。绑定模式=pbByName
  • 当参数为。绑定模式=pbByNumber
  • aeUpToFirst错误
  • aeOnErrorUndoAll(错误全部取消)
Sybase SQL Anywhere数据库 本地 aeUpToFirst错误
Teradata数据库 本地 aeOnErrorUndoAll(错误全部取消)

注:

命令执行

在执行Array DML之前,应用程序代码必须设置参数值数组。首先,通过给Params赋值来设置数组长度。数组大小。分配此属性值时,会将指定的数组长度隐式分配给所有参数ArraySize属性。因此,在分配给Params之前,Params集合必须不为空。数组大小。其次,为参数数组赋值。TADParam类有一组AsXXXs[AIndex:Integer]属性,类似于AsXXX属性以及接受作为第一个参数数组索引的其他属性和方法。例如:

FD查询1.SQL语言.文本 以下为:= '插入MyTab值(:p1,:p2,:p3)';
//此处FDQuery1.Params集合由3个参数填充
FD查询1.参数.阵列大小 以下为:= 100;
对于  以下为:= 0  100-1  开始
  FD查询1.参数[0].作为整数[] 以下为:= ;
  FD查询1.参数[1].AsStrings(作为字符串)[] 以下为:= “qwe”;
  FD查询1.参数[2].清除();
结束;

TFDCustomCommand、TFDQuery和TFDStoredProc具有执行(A时间:Integer=0;AOffset:Integer=0)方法。这里,ATimes定义数组的长度。AOffset是数组中第一项的索引。因此,该命令将从AOffset行开始执行(ATimes-AOffset)次。AT时间必须等于或小于Params。数组大小。例如:

FD查询1.执行(100, 0);

执行Array DML后,属性行受影响包含成功执行的次数,而不是所有执行受影响的总行数。例如:

显示消息(IntToStr公司(FD查询1.行受影响));

错误处理

TFDAdaptedDataSet、TFDQuery和TFDStoredProc能够使用捕获错误OnExecuteError(执行错误)事件处理程序。如果未分配错误处理程序且发生错误,则Execute将引发异常,RowsAffected将被更新。

如果TFDAdaptedDataSet。分配OnExecuteError事件处理程序后,它将获取原始异常对象、当前时间和偏移量,并可能返回AAction值,说明下一步要做什么。A错误。错误[…]包含一个或多个错误。A错误。错误[i]。RowIndex是失败的行索引。注意,对于语法错误或ATimes=1时,不会调用OnExecuteError。

例如:

程序 T形1.FDQuery1执行错误(A投标人: TObject(目标); A时间,
  A偏移: 整数; A错误: EFDDB发动机异常; 无功功率,无功功率 A操作: TFD错误操作);
开始
  如果 A错误.错误[0].种类 = 违反ekUK 然后
    A操作 以下为:= eaSkip公司
  其他的
    A操作 以下为:= eaFail(ea失败);
结束;

具体行为取决于DBMS及其相应的Array DML模式:


阵列DML模式 说明
aeOnErrorUndoAll(全部取消) 第一个错误时停止执行。所有成功应用的数组项都将被撤消。然后,FireDAC切换到逐个执行模式并重新执行整个阵列。这类似于aeUpToFirstError。请参阅下面的aeUpToFirstError。
aeUpToFirst错误 第一个错误时停止执行。将保存所有成功应用的数组项。DBMS返回第一个失败数组项的索引。RowsAffected=成功应用的数组项数。AError中的错误集合。错误[…]包含一个或多个引用单个失败行的错误。A错误。错误[i]。RowIndex是失败的行索引。
aeCollectAllErrors(收集所有错误) 将执行所有数组项。将保存所有成功应用的数组项。DBMS逐个返回每个失败数组项的索引。RowsAffected=成功应用的数组项数。AError中的错误集合。错误[…]为每一失败行包含一个错误。A错误。错误[i]。RowIndex是失败的行索引。

注释:设置资源选项。阵列DML大小到1隐式地将数组执行模式设置为aeUpToFirstError。要获取当前连接的DBMS Array DML模式,请使用:

如果 FD连接1.连接元数据Intf.阵列执行模式 = aeOnErrorUndoAll(错误全部取消) 然后
  ....


故障排除

正确设置参数很重要,包括设置字符串参数的属性Size。例如,在Oracle的情况下,当未明确指定Size时,FireDAC将为每个ftString/ftWideString参数分配4000字节。因此,对于10000个值,将分配40 Mb的缓冲区。如果有很多参数,那么应用程序可能会占用所有系统内存。

大多数DBMS都对数组DML大小有隐式限制。它取决于DBMS客户端库缓冲区大小或允许的最大网络数据包。当达到极限时,使用资源选项。阵列DML大小可以透明地将大型Array DML分割为几个较小的片。


示例1

使用IFDPhysCommand的阵列DML:

无功功率,无功功率
  oCmd命令: IFDPhys命令;
……
  具有 oCmd命令  开始
    命令文本 以下为:= '插入客户(ID,Name)值(:ID,:Name)';
    //设置参数类型
    参数[0].数据类型 以下为:= ft整数;
    参数[1].数据类型 以下为:= ftString(英尺字符串);
    参数[1].大小 以下为:= 40;
    //设置参数的数组大小
    参数.阵列大小 以下为:= 10000;
    //设置参数值
    对于  以下为:= 0  10000 - 1  开始
      参数[0].作为整数[] 以下为:= ;
      参数[1].AsStrings(作为字符串)[] 以下为:= “某人” + 国际贸易协定();
    结束;
    //执行批处理
    执行(10000, 0);
  结束;


示例2

具有TFDQuery和错误处理的阵列DML:

程序 T形1.FDQuery1执行错误(A投标人: T对象; A时间,
  A偏移: 整数; A异常: EFDDB发动机异常; 无功功率,无功功率 A操作: TFD错误操作);
开始
  案例 A异常.错误[0].种类 属于
  ekPK违规:
    开始
      //修复ID唯一
      FD查询1.参数[0].作为整数[A异常.错误[0].行索引] 以下为:= A异常.错误[0].行索引;
      A操作 以下为:= ea重试;
    结束;
  ekFK违规:
    //如果找不到RegionID为的Region,则跳过行
    A操作 以下为:= eaSkip公司;
  其他的
    A操作 以下为:= ea失败;
  结束;
结束;

程序 T形1.按钮1单击(A投标人: TObject(目标));
开始
  具有 FD查询1  开始
    SQL语言.文本 以下为:= '插入客户(ID,RegionID,Name,Note)值(:ID,:RegionID、:Name、:Note)';
    //设置参数类型
    参数[0].数据类型 以下为:= 英尺整数;
    参数[1].数据类型 以下为:= ft整数;
    参数[2].数据类型 以下为:= ftString(英尺字符串);
    参数[2].大小 以下为:= 40;
    参数[].数据大小 以下为:= ftMemo公司;
    //设置参数的数组大小
    参数.阵列大小 以下为:= 10000;
    //设置参数值
    对于  以下为:= 0  10000 - 1  开始
      如果  国防部 100 = 0 然后
        //强制PK冲突
        参数[0].作为整数[] 以下为:=  - 1
      其他的
        参数[0].作为整数[] 以下为:= ;
      参数[1].作为整数[] 以下为:= 为客户获取区域ID();
      参数[2].AsStrings(作为字符串)[] 以下为:= “某人” + 国际贸易协定();
      参数[].清除();
    结束;
    //执行批处理
    执行(10000, 0);
  结束;
结束;

另请参见

样品