idata数据访问组件库(RX11)版本: 2022-09-20
下载: idata 数据组件库 for RAD Studio RX10.3.x (260) 发布于:2020-02-20 使用 bin\dclidata260.bpl 安装组件
下载: idata 数据组件库 for RAD Studio 11 (280) 发布于:2021-09-22 使用 bin\dclidata280.bpl 安装组件
idata 组件是基于 Indy10 开发的, 由服务端作为中间层服务器,建立客户端与后台数据库的通信。
idata是高效、安全、稳定的数据访问组件,你可以构建自己的登录认证系统,同时数据传输(SQL指令、参数、数据集)是经过压缩与动态加密的。
idata的DataSet(数据集组件)是基于内存访问的高效率组件,移动记录、数据统计、数据过滤、数据访问均有优异的体现。
idata是RTL组件,可应用于 Win32、Win64、Linux64、Android、Android64、OSX32、iPad、iPhone 系统的Delphi与C++Builder开发。
类与组件表
场合 | idata | 名称 | 说明 |
客 户 端 | 类 | TIdField | 内存数据访问类 |
TIdCustomDataSet | 数据集基类模型 | ||
组件 | TIdMemDataSet | 内存表组件 | |
TIdDBConnection | 数据库连接器组件 | ||
TIdDBQuery | 数据访问组件 | ||
服 务 端 | 类 | TIdDBPoolConnector | 池连接器类 |
TIdContextSession | 服务端会话类 | ||
组件 | TIdDBPoolController | 池控制器组件 | |
TIdDBPoolMethod | 池方法组件 | ||
TIdDBServer | 服务器组件 |
CSDN_ID: sczyq 联系QQ:79896009
TIdField
IdField 是内存数据访问类, 你可以通过内部记录索引号快速访问内部数据。注意:当数据正要编辑(State = dsEdit)并且尚未提交时,访问到的当前记录数据是编辑前的。
声明:
TIdField = class;
TIdField 是内存数据访问类。
属性:
属性 | 说明 |
DataSet: TIdCustomDataSet | 数据集类指针 |
Field: TField | 所关联的 TField 类 |
DataType: TFieldType | 与 TField 的属性相同 |
DataSize: Integer | |
IsBlob: Boolean | |
IsVirtual : Boolean | 是否来自VirtualFields 的 Field |
IsNull[AIndex: Integer] : Boolean | 识别该记录的值是否是 NULL |
AsBytes[AIndex: Integer] : TBytes | 将该记录的值转换为相应的数据类型,顾名思义的,不适当的数据转换可能会产生异常。 |
AsVariant[AIndex: Integer] : Variant | |
AsString[AIndex: Integer] : String | |
AsInteger[AIndex: Integer] : Longint | |
AsBoolean[AIndex: Integer] : Boolean | |
AsFloat[AIndex: Integer] : Double | |
AsCurrency[AIndex: Integer] : Currency | |
AsDateTime[AIndex: Integer] : TDateTime | |
AsLargeInt[AIndex: Integer] : Largeint | |
AsSQLTimeStamp[AIndex: Integer] : TSQLTimeStamp | |
AsCardinal[AIndex: Integer] : Cardinal | |
AsExtended[AIndex: Integer] : Extended | |
AsSingle[AIndex: Integer] : Signle |
例如:采用 AsBytes 方法访问 Blob 字段
Var LStream : TMemoryStream; LBytes : TBytes; begin LStream := TMemoryStream.Create; try // IdDataSet : TIdCustomDataSet LBytes := IdDataSet.IdFieldByName(‘Picture’).AsBytes[IdDataSet.DataIndex]; LStream.Write(LBytes, Length(LBytes)); // Image : TImage Image.Picture.Bitmap.LoadFromStream(LStream); End; finally LStream.Free; end; end; |
TIdCustomDataSet
TIdCustomDataSet 是idata的数据集基类模型。具有以下特点:
- 具有真实Field(SQL)与虚拟Field(VirtualFields)合成一个数据集的功能。
- 数据快速访问,不必移动数据集记录即可访问数据,使用 TIdField 与数据索引号。
- 内部记录快速过滤器,使用OnFilterData 比使用OnFilterRecord 性能更优秀。
- Blob 数据内存块采用计数器,减少内存使用量与内存块创建与释放。
声明:
TIdCustomDataSet = class(TDataSet);
属性:
DataCount: Integer
获取内部数据总数, 与数据是否过滤 Filtered 无关,
例如: 总记录100条, 过滤后是80条 | ||
Filtered | DataCount | RecordCount |
False | 100 | 100 |
True | 100 | 80 |
快速统计代码比较:
常规写法, 记录访问模式 |
function TForm1.GetSumValue : Currency; var LField : TField; OldRecNo : Integer; Begin Result := 0; // LIdDataSet : TIdCustomDataSet LField := LIdDataSet.FieldByName(‘Value’); OldRecNo := LIdDataSet.RecNo; try LIdDataSet.DisableControls; LIdDataSet.First; while (not LIdDataSet.Eof) do begin Result := Result + LField.AsCurrency; LIdDataSet.Next; end; finally LIdDataSet.RecNo := OldRecNo; LIdDataSet.EnableControls; end; end; |
idata写法, 内存数据访问模式 |
function TForm1.GetSumValue : Currency; var I : Integer; LIdField : TIdField; Begin Result := 0; // LIdDataSet : TIdCustomDataSet LField := LIdDataSet.IdFieldByName(‘Value’); // 常规写法, 也是数据未过滤或者全部记录统计 For I := 0 TO LIdDataSet.DataCount – 1 do Result := Result + LIdField.AsCurrency[I]; { // 如果记录已经过滤, 只统计已经过滤后的, 就应该这样写 For I := 1 TO LIdDataSet.RecordCount do Result := Result + LIdField.AsCurrency[LIdDataSet.DataIndexOf(I)]; } end; |
DataIndex: Integer
获取当前记录的数据索引号
LookupOptions: TLookupOptions
使用Lookup 方法时使用的查找选项
ReadOnly: Boolean
数据集是否是只读的
Sort: String
进行数据记录重排序, 允许多字段排序。
表达式格式: 字段名与关键字并且关键字之间用空格分开, 多个字段之间用分号。
关键字,与次序无关 | 说明 |
DESC | 倒序 |
CASE | 大小写不敏感的, 仅适用于字符数据类型 |
例如: 将Price (价格)作为从少到大排序,Name (名称)倒序,并且大小写不敏感。
Sort := ‘Price;Name DESC CASE’;
PostUnsorting: Boolean
在执行 Post 数据时禁止数据重排序。该属性只会在当前正在排序字段的值改变后起作用。禁止数据重排序的作用是当Post成功后,当前展现数据的次序不变。
VirtualFields: TFieldDefs
始终存在的本地定义的 Field
如果VirtualFields 定义的 Field 名称与 SQL查询结果的字段有重名,则数据类型由SQL查询决定。
例:
VirtualFields 定义 | ||
Name | DataType | Size |
NO | ftAutoInc | |
TEXT | ftString | 32 |
SQL字段名与VirtualFields字段名不重叠的结果 | |||
SQL 查询 | SELECT Id, Name, Value FROM TABLE_1 | ||
Name | DataType | Size | 说明 |
Id | ftInteger | 类型来自于 TABLE_1 | |
Name | ftWideString | 40 | |
Value | ftCurrency | ||
NO | ftAutoInc | 类型来自于 VirtualFields 定义 | |
TEXT | ftString | 32 |
SQL字段名与VirtualFields字段名有重叠的结果 | |||
SQL 查询 | SELECT Id AS No, Name, Value FROM TABLE_1 | ||
Name | DataType | Size | 说明 |
No | ftInteger | 类型来自于 TABLE_1 | |
Name | ftWideString | 40 | |
Value | ftCurrency | ||
TEXT | ftString | 32 | 类型来自 VirtualFields |
VirtualFields 的 Field 类型属性定义。
ftAutoInc: 初始数据的序号,从1开始,只增不减,即使是中间插入。
数值型:初始数据是0
字符型:初始数据是空
Blob 类型:初始数据是NULL
VirtualFields 定义使数据集操作更加灵活, 程序操作更加方便。
方法:
function IdFieldOf(const AField: TField) : TIdField;
根据字段类获取 TIdField 类
参数 | 说明 |
AField | 字段类指针 |
function IdFieldByName(const AFieldName: String) : TIdField;
根据字段名获取 TIdField 类
参数 | 说明 |
AFieldName | 字段名 |
function DataIndexOf(ARecNo : Integer) : Integer;
将记录号转换为数据索引号
参数 | 说明 |
ARecNo | 记录号 |
function FindDataIndex(const KeyFields: String;
const KeyValues: Variant;
Options: TLocateOptions = []) : Integer;
查找符合条件的首条数据所在的记录, 返回数据索引号
参数 | 说明 | |
KeyFields | 字段名列表 | 参照 Locate 方法 |
KeyValues | 值列表 | |
Options | 查找选项 |
function FindRecNo(const KeyFields: String;
const KeyValues: Variant;
Options: TLocateOptions = []): Integer;
查找符合条件的首条数据所在的记录, 返回记录号
参数 | 说明 | |
KeyFields | 字段名列表 | 参照 Locate 方法 |
KeyValues | 值列表 | |
Options | 查找选项 |
procedure SaveToStream(AStream: TStream;
AExcludeVirtual : Boolean = False);
保存数据到idata数据格式流, 与记录是否过滤相关
参数 | 说明 |
AStream | 目标流,必须已经初始化 |
AExcludeVirtual | 是否排除由VirtualFields 产生的字段 |
procedure SaveToFile(AFileName: String;
AExcludeVirtual : Boolean = False);
保存数据到idata数据格式文件, 与记录是否过滤相关
参数 | 说明 |
AFileName | 文件名,建议包括完成路径 |
AExcludeVirtual | 是否排除由VirtualFields 产生的字段 |
事件:
OnFilterData : TIdFilterDataEvent 记录过滤器事件
与 OnFilterRecord 过滤器事件作用相同,但OnFilterRecord 事件优先,只有不存在OnFilterRecord 事件的情况下,才会使用OnFilterData 事件。
但是,OnFilterRecord 事件是记录型的,DataSet在执行过滤时,需要移动记录号。而OnFilterData 是内存数据型的,执行过滤时,不会移动记录号,因此具有更高的效率。
OnFilterRecord 与 OnFilterData的代码比较:
OnFilterRecord 记录访问过滤模式 |
procrdure TForm1.IdDBQuery1FilterRecord(DataSet: TDataSet; var Accept: Boolean); begin // 执行到这里时,DataSet 会移动记录号,以当前记录访问缓冲区数据 Accept := IdDBQuery1.FieldByName(‘Value’).AsCurrency > 100; end; |
OnFilterData 内存数据访问过滤模式 |
procrdure TForm1.IdDBQuery1FilterData(DataSet: TDataSet; const Index : Integer; var Accept: Boolean); begin // 执行到这里时,DataSet 不会移动记录号,使用Index去直接访问内存数据 Accept := IdDBQuery1.IdFieldByName(‘Value’). AsCurrency[Index] > 100; end; |
讨论: 为什么内存数据访问会比记录访问效率更高?
内存数据访问, 是直接从内存中提取数据, 原理是: DATA -> VALUE
记录访问, 是间接的通过缓存提取数据, 原理是:DATA -> BUFFER -> VALUE 即:每一次移动记录, 都会将当前内存记录复制到缓存区, 然后再从缓存中提取值,而且DataSet每一次移动记录(即使DisableControls), 都需要执行一批相应的指令,因而影响了效率。
TIdMemDataSet
TIdMemDataSet 是内存表组件。
声明:
TIdMemDataSet = class(TIdCustomDataSet);
方法:
procedure CreateDataSet;
创建由VirtualFields 定义的字段并且打开空数据集
procedure CreateFieldsFromDataSet(ADataSet: TDataSet);
创建由源数据集相同的字段并且打开空数据集,如果存在VirtualFields 定义的字段并且字段名称未重叠,能够一并创建。源数据集的记录不会复制过来。
参数 | 说明 |
ADataSet | 源数据集 |
procedure AddRecordsFromDataSet(ADataSet: TDataSet);
追加源数据集的记录到当前数据集,字段名或数据类型不相同的数据会被抛弃,使用该方法前,数据集必须是活动的。
参数 | 说明 |
ADataSet | 源数据集 |
procedure LoadFromDataSet(ADataSet: TDataSet);
装载源数据集的数据到当前数据集,该方法的作用就是执行 CreateFieldsFromDataSet和 AddRecordsFromDataSet。
参数 | 说明 |
ADataSet | 源数据集 |
procedure LoadFromStream(AStream: TStream);
从idata数据格式流中装载数据到当前数据集,如果存在VirtualFields 定义的字段并且字段名称未重叠,能够一并创建。
参数 | 说明 |
AStream | 目标流,是使用 SaveToStream 导出的 |
procedure LoadFromFile(AFileName: String);
从idata数据格式文件中装载数据到当前数据集, 如果存在VirtualFields 定义的字段并且字段名称未重叠,能够一并创建。
参数 | 说明 |
AFileName | idata数据格式文件名,建议使用完整路径 |
procedure EmptyDataSet; 清空数据。
TIdDBConnection
TIdCustomDBConnection 是idata的数据库通讯类模型。TIdDBConnection 是idata的数据库通讯组件。是建立与服务端(TIdDBServer)的交互的必须工具。具有以下特点:
- 自动断线重连功能,即使当前的网络环境已经改变。
- 线程安全,不同线程间与服务端数据的交互自动采用安全锁。
- 直接执行SQL语句(ExecuteSQL),或将SQL数据集导出到数据集流(QueryToStream, idata数据流格式)。
- 与TIdDBServer结合,可以自定义的用户登录校验方式。
声明:
TIdCustomDBConnection = class(TCustomConnection);
TIdDBConnection = class(TIdCustomDBConnection);
属性:
Server : String
服务器的主机地址,可以是域名。
如果服务器端口号不是默认端口是698,那么在主机后加上端口号。格式是:<主机>[:<端口>]
IP版本 | 主机 | 端口 | 值 |
IPv4 | 192.168.1.100 | 698 | 192.168.1.100 |
3333 | 192.168.1.100:3333 | ||
IPv6 | [1::1] | 698 | [1::1] |
3333 | [1::1]:3333 |
IPVersion : TIdIPVersion
连接服务器采用的IP协议,默认是IPv4。
ReuseSocket : TIdReuseSocket
服务器是否重用连接。
Username : String
登录服务器的用户名,是否需要决定于服务器。
Password : String
登录服务器的口令,是否需要决定于服务器。
BlockSize : Word
数据通信的每个块最少值,单位是KB,默认值是512KB,该值在大数据量的情况下,起作用。
值 | 响应速度 | 通信次数 |
变大 | 劣 | 优 |
变小 | 优 | 劣 |
CommandTimeout : Word
命令执行超时等待时间,单位是秒,当向服务器发送SQL指令后,如果超过这个等待时间无响应,视为超时,并抛出异常(有些情况是实际是执行成功了的, 只是执行时间过长而已)。
ConnectionTimeout : Word
连接服务器的超时等待时间,单位是秒,当准备向服务器连接后,如果超过这个等待时间无响应,视为超时,并抛出异常。
Identity : Largeint
服务器与客户端通信的唯一的连接码,每次连接服务器都会分配一个不同的连接码,该属性是只读的。
DBProduct : String
服务器端后台数据库产品名称,客户获取该数据库产品名称的作用,主要是用于客户端开发时编写SQL语句时,可以根据该属性编码不同的SQL指令。
事件:
OnLock : TNotifyEvent
当锁定Socket时发生该事件,一般情况下是在开始执行SQL前。
OnUnlock : TNotifyEvent
当解锁Socket时发生该事件,一般情况下是执行SQL并已经完成后。
TIdDBMakeUserInfo = procedure (ASender : TObject;const AParams : TParams);
OnMakeUserInfo : TIdDBMakeUserInfo
连接服务器时发生该事件。需要提供哪些参数由服务器决定,如果没有编写相应的事件,系统会自动加入 Username 与 Password 到这个参数列表。
参数 | 说明 |
ASender | 调用者 |
AParams | 客户端登录参数表 |
TIdDBStoredProcScript = procedure(const AStoredProc, AParameter: String;
const IsOpen : Boolean; var ASQL : String);
OnStoredProcScript : TIdDBStoredProcScript
编写该事件,是为了适应不同的后台数据库系统调用存储过程的方法。
当需要获取存储过程SQL脚本时, 发生该事件。如果未编写该事件, 则按默认生成SQL脚本。
参数 | 说明 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
IsOpen | 当前过程是否用来获取数据集 |
ASQL | 输出的SQL脚本 |
使用不同的数据库系统, MSSQL 与 MYSQL
var DBConn : TIdDBConnection; if DBConn.DBProduct = ’MSSQL’ then ASQL := ‘EXEC ‘ + AStoredProc + ‘ ‘ + AParameter + ‘;’ else if DBConn.DBProduct = ’MYSQL’ then ASQL := ‘CALL ‘ + AStoredProc + ‘(‘ + AParameter + ‘);’ ; |
TIdDBSQLAction = (saOpen, saAppend, saUpdate, saDelete, saExecute);
TIdDBSQLExceptionEvent = procedure (Sender: TObject; SQL : TStrings;
const Action : TIdDBSQLAction; E: Exception);
OnSQLException : TIdDBSQLExceptionEvent
当SQL发生异常时发生该事件。
参数 | 说明 |
Sender | 产生异常的组件类 |
SQL | SQL 语句列表 |
Action | 当前的动作 |
E | 异常类 |
OnConnected : TNotifyEvent
当连接成功时发生该事件。
OnDisconnected : TNotifyEvent
当断开连接时发生该事件。
方法:
Host : String 获取服务器的主机地址
Port : String 获取服务器的端口
procedure Lock; 锁定 Socket
procedure Unlock; 解锁 Socket。
锁定与解锁是配套的,建议使用 try … finally … end 异常。
try Lock; … finally Unlock end; |
在使用TIdDBQuery执行SQL指令或时,能够自动锁定与解锁,你无需编写这些锁定与解锁的代码Socket。只有在使用Socket执行扩展的协议时,才需要用到Lock 和 Unlock。
function StoredProcScript(AStoredProc, AParameter: String; IsOpen : Boolean) : String;
根据存储过程名称与参数串, 获取SQL指令,该过程与事件 OnStredProcScript 相关。
参数 | 说明 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
IsOpen | 当前过程是否用来获取数据集 |
Procedure QueryToStream(AStream : TStream; ASQL : TStrings; AParams : AParams = nil);
执行查询SQL指令,将结果输出到流。
参数 | 说明 |
AStream | 目标流,指针必须初始化 |
ASQL | 多行SQL指令表 |
AParams | 与SQL指令表对应的参数,无参数可省略 |
Procedure QueryToStream(AStream : TStream; ASQL : String);
Procedure QueryToStream(AStream : TStream; ASQL : String; AParams : AParams);
执行查询SQL指令,将结果输出到流, 这是。
参数 | 说明 |
AStream | 目标流,指针必须初始化 |
ASQL | SQL指令 |
AParams | 与SQL指令表对应的参数,无参数可省略 |
Procedure QueryToStream(AStream : TStream; AStoredProc, AParameter : String);
Procedure QueryToStream(AStream : TStream; AStoredProc, AParameter : String; AParams : AParams);
参数 | 说明 |
AStream | 目标流,指针必须初始化 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
AParams | 与存储过程的参数串对应的参数,无参数可省略 |
Procedure ExecuteSQL(ASQL : TStrings; AParams: TParams = nil);
执行SQL指令,执行时自动加锁与解锁Socket。
参数 | 说明 |
ASQL | 多行SQL指令表 |
AParams | 与SQL指令表对应的参数,无参数可省略 |
Procedure ExecuteSQL(ASQL : String);
Procedure ExecuteSQL(ASQL : String; AParams: TParams);
参数 | 说明 |
ASQL | SQL指令 |
AParams | 与SQL指令表对应的参数,无参数可省略 |
Procedure ExecuteSQL(AStoredProc, AParameter: String);
Procedure ExecuteSQL(AStoredProc, AParameter: String; AParams: TParams);
执行SQL指令,返回少于0则表示失败的。执行时自动加锁与解锁Socket。
参数 | 说明 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
AParams | 与存储过程的参数串对应的参数,无参数可省略 |
Procedure BeginTrans; 启动事务, 启动前自动锁定Socket。
Procedure CommitTrans; 提交事务,执行成功自动解锁Socket。
Procedure RollbackTrans; 回滚事务,执行成功自动解锁Socket。
建议使用 try … exception … end 异常处理。
try BeginTrans; … CommitTrans; exception RollbackTrans; end; |
TIdDBQuery
TIdDBQuery 是SQL数据访问组件。具有以下特点。
- 可以定义数据集是本地内存方式或连线方式,即数据修改后是否要提交到服务端。
- 当网络环境改变时(TIdDBConnection断线时),数据集不会被关闭。当准备将编辑数据提交到服务器时,TIdDBConnection 会重连。
- TIdDBCustomDataSet 所具有的特点。
4. 即使属性 LocalEditor = False ,由 VirtualFields 定义而产生的字段,数据修改后,总是不会提交到远程服务器。
声明:
TIdDBQuery = class(TIdCustomDataSet);
属性:
property Connection : TIdCustomDBConnection
远程SQL数据连接器。
property SQL : TStrings
SQL指令集。
property Params : TParams
SQL指令内包含的参数列表。
property LocalEditor : Boolean
决定数据编辑器是否是本地的。这个值必须是数据集在关闭的状态时才能改变。
如果这个值为 True,那么,这个 TIdDBQuery 就是一个内存表,数据编辑后不会提交到SQL服务器。
如是果这个值为 False(默认),那么,当发生数据编辑提交,记录删除等操作, 同步提交到SQL服务器,并且必须成功, 否则产生异常。
方法:
procedure OpenSQL(ASQL : String);
打开由参数指令决定的数据。
参数 | 说明 |
ASQL | SQL指令 |
这个方法只是简化了代码编写, 与Open 不同点在于,Open 方法必须先定义属性SQL指令,然后才能Open。
如果存在VirtualFields 定义的字段并且字段名称与SQL返回结果未重叠,能够一并创建, 具体内容请见 TIdCustomDataSet 的属性VirtualFields 说明。
procedure OpenSQL(AStoredProc, AParameter : String);
打开由存储过程及参数串决定的数据。
参数 | 说明 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
procedure ExecSQL(ASQL : String = ‘’);
执行SQL。
参数 | 说明 |
ASQL | SQL指令,如果空指令由执行属性SQL定义的指令 |
这个方法也是简化了代码编写,但如果参数存在SQL指令,则不会改变属性SQL的定义。
procedure ExecSQL (AStoredProc, AParameter : String);
执行存储过程。
参数 | 说明 |
AStoredProc | 存储过程名称 |
AParameter | 存储过程的参数串 |
事件:
property OnFetchProgress : TDataSetNotifyEvent
当SQL连接器获取到一个数据块,并处理完该数据块时产生该事件,SQL获取数据可能由多个数据块组成。得到该事件表示SQL正在处理。
property OnFetchComplete : TDataSetNotifyEvent
当SQL获取并处理完全部数据块时产生该事件,得到该事件表示SQL已经完成。
TIdDBPoolConnector
池连接器类,你要通过控制器的方法获取并回收,而不是创建与删除。
声明:
TIdDBPoolConnector = class(TComponent);
属性:
property Controller : TIdDBPoolController;
池控制器。
property Connection : TCustomConnection;
源数据库连接,来自池初始化方法 DoInitialize。
property DataSet : TDataSet;
数据集,一般是Query组件,来自池初始化方法 DoInitialize。
property SQL : TStrings;
SQL指令。
property Params : TParams;
SQL指令内包含的参数列表。
property Activity : TDataTime
当前连接器最后活动的时间。
方法:
procedure Clear;
清空SQL指令与参数, 并关闭DataSet数据集。
procedure CloseSQL;
关闭数据集, 如何做决定于池方法 DoCloseSQL。
procedure OpenSQL;
打开由参数指令决定的数据, 如何做决定于池方法 DoOpenSQL。
procedure ExecSQL;
执行由参数指令决定的数据, 如何做决定于池方法 DoExecSQL。
procedure BeginTrans;
启动一个数据库事务, 如何做决定于池方法 DoBeginTrans。
procedure CommitTrans;
提交当前数据库事务, 如何做决定于池方法 DoCommitTrans。
procedure RollbackTrans;
回滚当前数据库事务, 如何做决定于池方法 DoRollbackTrans。
TIdContextSession
服务器会话类与协议库。你无需创建该类,在一些服务器事件中会用到这个类。
声明:
TIdContextSession = class(TIdServerContext);
属性:
Connector : TIdDBPoolConnector;
源数据库连接池连接器。
Identity : Largeint;
当前会话种子。
Username : String;
用户名。
BlockSize : Word;
数据传送块大少,参照 TIdDBConnection.BlockSize 属性。
LoginTime : TDateTime;
登录时间。
property Activity : TDataTime
当前连接最后活动的时间。
TIdDBPoolMethod
源数据库连接池控制器方法。编写这些事件过程,决定于你采用哪种源数据库连接方式(BDE/ADO/FireDAC/DBX/...)。
声明:
TIdCustomDBPoolMethod = class(TComponent)
TIdDBPoolMethod = class(TIdCustomDBPoolMethod)
事件:
TDBConnectorInitialize = procedure(AOwner : TComponent;
var AConnection : TCustomConnection; var ADataSet : TDataSet) of object;
OnInitialize: TIdDBPoolConnectorInitialize;
初始化池连接器组件事件,你必须创建池连接器的 AConnection 与 ADataSet 组件。
参数 | 说明 |
AOwner | 创建池连接器组件的属主 |
AConnection | 源数据库连接组件 |
ADataSet | 数据集的指针 |
OnCloseSQL: TIdDBPoolConnectorMetdod;
关闭数据集时启动该事件。
OnOpenSQL: TIdDBPoolConnectorMetdod;
打开SQL指令时启动该事件。
OnExecSQL: TIdDBPoolConnectorMetdod;
执行SQL指令时启动该事件。
OnBeginTrans: TIdDBPoolConnectorMetdod;
开始一个数据库事务时启动该事件。
OnCommitTrans: TIdDBPoolConnectorMetdod;
提交当前数据库事务时启动该事件。
OnRollbackTrans: TIdDBPoolConnectorMetdod;
回滚当前数据库事务时启动该事件。
讨论:
你也可以通过继承TIdCustomDBPoolMethod 的类来提供给池控制器,而不采用TIdDBPoolMethod 组件方法。
例如:采用 ADO 方式连接源数据库的方法类 ADOPoolMethod.pas
unit ADOPoolMethod; { 本代码配合数据库连接池组件使用, 仅适用于 ADO 环境 使用本代码后, 你就无需再编写 TIdDBPoolMethod 的事件处理过程. 只需要将这个 Pas 加入到你的工程, 然后创建该TADODBPoolMethod类给控制器 IdDBPoolController1.PoolMethod := TADODBPoolMethod.Create(Self, ConnStr); 由于 ADO 是 Windows 的 COM 组件, 而连接池初始化是在线程中完成的 所以你必须编写 TDBPoolController 组件的 OnBeforeRun 与 OnAfterRun 事件方法 进行 COM 的初始化与回收 procedure TMyServer.IdDBPoolController1BeforeRun(ASender : TObject); begin CoInitialize(nil); end; procedure TMyServer.IdDBPoolController1AfterRun(ASender : TObject); begin CoUninitialize(); end; } interface uses System.Classes, Data.DB, idata.Pool, Data.Win.ADODB; type TADODBPoolMethod = class(TIdCustomDBPoolMethod) private FConnectionString : String; function GetQuery(AConnector : TIdDBPoolConnector) : TADOQuery; protected procedure DoInitialize(AConnector : TIdDBPoolConnector; var AConnection : TCustomConnection; var ADataSet : TDataSet); override; procedure DoCloseSQL(AConnector : TIdDBPoolConnector); override; procedure DoOpenSQL(AConnector : TIdDBPoolConnector); override; procedure DoExecSQL(AConnector : TIdDBPoolConnector); override; procedure DoBeginTrans(AConnector : TIdDBPoolConnector); override; procedure DoCommitTrans(AConnector : TIdDBPoolConnector); override; procedure DoRollbackTrans(AConnector : TIdDBPoolConnector); override; public constructor Create(AOwner : TComponent; AConnectionString : String); reintrodce; end; implementation constructor TADODBPoolMethod.Create(AOwner : TComponent; AConnectionString : String); begin inherited Create(AOwner); FConnectionString := AConnectionString; end; function TADODBPoolMethod.GetQuery(AConnector :TIdDBPoolConnector) :TADOQuery; var I : Integer; LParam : TParam; LParameter : TParameter; begin Result := TADOQuery(AConnector.DataSet); Result.Close; Result.SQL.Clear; Result.SQL.Assign(AConnector.SQL); for I := 0 to AConnector.Params.Count - 1 do begin LParam := AConnector.Params[I]; LParameter := Result.Parameters.FindParam(LParam.Name); if not Assigned(LParameter) then LParameter := Result.Parameters.AddParameter; LParameter.Assign(LParam); end; end; procedure TADODBPoolMethod.DoInitialize(AConnector : TIdDBPoolConnector; var AConnection : TCustomConnection; var ADataSet : TDataSet); begin AConnection := TADOConnection.Create(AConnector); TADOConnection(AConnection).ConnectionString := FConnectionString; AConnection.LoginPrompt := False; ADataSet := TADOQuery.Create(AConnector); TADOQuery(ADataSet).Connection := TADOConnection(AConnection); end; procedure TADODBPoolMethod.DoCloseSQL(AConnector : TIdDBPoolConnector); var LQuery : TADOQuery; begin LQuery := TADOQuery(AConnector.DataSet); LQuery.Close; LQuery.SQL.Clear; end; procedure TADODBPoolMethod.DoOpenSQL(AConnector : TIdDBPoolConnector); begin GetQuery(AConnector).Open; end; procedure TADODBPoolMethod.DoExecSQL(AConnector : TIdDBPoolConnector); begin GetQuery(AConnector).ExecSQL; end; procedure TADODBPoolMethod.DoBeginTrans(AConnector : TIdDBPoolConnector); begin TADOConnection(AConnector.Connection).BeginTrans; end; procedure TADODBPoolMethod.DoCommitTrans(AConnector : TIdDBPoolConnector); begin TADOConnection(AConnector.Connection).CommitTrans; end; procedure TADODBPoolMethod.DoRollbackTrans(AConnector : TIdDBPoolConnector); begin TADOConnection(AConnector.Connection).RollbackTrans; end; end. |
TIdDBPoolController
源数据库连接池控制器。
声明:
TIdDBPoolController= class(TComponent);
属性:
Active : Boolean;
池控制器是否在开启状态。
PoolCount : Integer;
当前池连接器计数。
AlwaysCount : Word;
充许保持连接器的数量。当池控制器开启后,并不会立刻创建这个数量的连接器(TIdDBPoolConnector),当连接器数达到这个量时,这些连接器会一直保持,直到池控制器关闭。连接器数超过这个量时,多余的会被释放掉。
IdlenessTimeout : Word;
当某个连接器空闲了这个时间(秒)后,并且连接器总数多于充许保持数时自动释放掉。
PoolMethod : TIdCustomDBPoolMethod;
连接器方法。
方法:
function Acquire(ASession : TObject) : TIdDBPoolConnector;
获取一个连接器。
procedure Recovery(AConnector : TIdDBPoolConnector);
回收一个连接器。
事件:
AfterRun : TNotifyEvent;
完成后事件,适用于Windows 系统释放线程COM。
BeforeRun : TNotifyEvent;
启动时的事件,适用于Windows 系统初始化线程COM。
OnPoolChanged : TNotifyEvent;
连接器的数量改变时启动该事件。
OnSQLException : TDBSQLExceptionEvent;
当SQL发生异常时发生该事件。
TIdDBServer
数据库服务器组件。是提供客户端与Database的数据交互中间件。
声明:
TIdCustomDBServer = class(TIdCustomTCPServer);
TIdDBServer = class(TIdCustomDBServer);
属性: (由 Indy10 的 TIdCustomTCPServer 提供的属性、方法、事件不再列出。)
DBController : TIdDBPoolController;
源数据库连接池控制器。
DBProduct : String;
源数据库产品标识, 参照 TIdDBConnection.DBProduct 属性。
LoginTimeout : Word;
客户端登录超时设置(秒)。
TransactionTimeout: Word;
事务超时设置(秒)。
InactiveTimeout: Word;
客户端会话超时设置(秒),某个连接在这个时间内无会话的即被判定为超时并断开这个他。
事件:
OnAfterRun : TNotifyEvent;
完成后事件,适用于Windows 系统释放线程COM。
OnBeforeRun : TNotifyEvent;
启动时的事件,适用于Windows 系统初始化线程COM。
TIdDBLoginVerifyMethod = procedure(ASession : TIdContextSession;
AParams : TParams; var AStatus: Boolean) of object;;
OnLoginVerify : TIdDBLoginVerifyMethod;
客户端登录时使用该事件,该事件内定义了客户端登录所需提供的参数,根据这些参数判定登录是否成功。
参数 | 说明 |
ASession | 客户端会话类,你可以通过这个类去获取池连接器 |
AParams | 客户端提供的登录参数表 |
AStatus | 返回值,登录成功时置为 True |
如果没有写该事件过程,登录总是成功的(匿名的)。
该事件决定了客户端登录事件的编写方式, 参见 TIdDBConnection.OnMakeUserInfo 事件说明。
OnExtendProtocol : TIdDBExtendProtocolMethod;
服务端扩展协议,当客户端发送了无法识别的协议时,触发该事件,目前是保留的。
TIdDBGetPrimaryKeyMethod = procedure(ASession : TIdContextSession;
const ATableName : String; var AFieldNames : String) of object;
OnGetPrimaryKey : TIdDBGetPrimaryKeyMethod;
获取表主键字段的事件。不同的数据库产品获取表主键的方式不相同,主键主要应用在TIdDBQuery 数据提交时使用。
参数 | 说明 |
ASession | 客户端会话类,你可以通过这个类去获取池连接器 |
ATableName | 表名 |
AFieldNames | 返回字段列表,每个字段后加上半角分号 |