Databases/zh CN
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
italiano (it) │
日本語 (ja) │
português (pt) │
русский (ru) │
中文(中国大陆) (zh_CN) │
References:
Tutorials/practical articles:
Databases |
本文介绍了Lazarus和数据库。下表给出了 Lazarus 支持的数据库。
请只安装必要的数据库组件,如数据库需用到客户端库则应先安装客户端库。否则由于缺少文件,Lazarus 可能会无法启动。因为数据库组件无法卸载,一旦有问题 Lazarus 就得重装。
支持的数据库
数据库 | 软件包名 | 是否需要客户端库 | 是否需要服务器端 | 支持的版本 | 支持的平台 |
---|---|---|---|---|---|
Advantage | TAdsDataSet | 是 | 否 | 10.1 以上 | i386: Linux、Win32 |
DBase | DBFLaz | 否 | 否 | III+, IV, VII | 所有 |
TurboPower FlashFiler | FlashFiler | 否 | 否 | - | Win 32、(win64?) |
In memory | memds | 否 | 否 | - | 所有 |
In memory | bufdataset | 否 | 否 | - | 所有 |
Firebird | SQLdb | 是 | 依赖于1 | 1 - 2.5 | i386: Linux、Win32 |
(Visual) FoxPro | DBFLaz | 否 | 否 | 2.0, 2.5, 3.0 (不完全) | 所有 |
Interbase | SQLdb | 是 | 是 | 4 - 6 | i386: Linux、Win32 |
Microsoft SQL Server | SQLdb | 是 | 是 | 6- | FPC 2.6.2+. Linux、macOS、Win32、可能 *BSD、可能 Solaris2 |
MySQL | SQLdb | 是 | 是 | 3.0 - 5.5 | i386: Linux、Win32 |
ODBC | SQLdb | 是 | 有依赖条件 | 3.x 3 | i386: Linux、Win32 |
Oracle | SQLdb | 是 | 是 | - | - |
Paradox | TParadoxDataSet | 否 | 否 | 最高至7级表(以上?) | 所有 |
Paradox | TParadox | 是 | 否 | Win32 | |
PostgreSQL | SQLdb | 是 | 是 | 6.6 - 8 | i386: Linux、Win32 |
Sybase Adaptive Server Enterprise (ASE) | SQLdb | 是 | 是 | 任何 | Linux、macOS、Win32、可能 *BSD, 可能Solaris2) |
SQLite | SQLdb | 是 | 否 | sqlite3 | 所有 |
SQLite | SQLite(3)Laz | 是 | 否 | sqlite2、sqlite3 | 所有 |
Text 文件 | sdf | 否 | 否 | - | 所有 |
ZMSQL | zmsql | 否 | 否 | ? | ? |
注1: 可在 Windows 和 Linux(可能也包括 macOS)中使用嵌入版的 Firebird,或者连到运行于 Windows/Unix/macOS/FreeBSD/其他 Firebird 支持平台中的 Firebird 服务器。
注2: 这些连接库用 FreeTDS 作为驱动程序,FreeTDS 的文档指出,至少应该可在这些平台下编译。Windows x86/x64 版本可在此下载:[1] 和 [2]
注3: 这里是指 ODBC 标准的版本,而非驱动程序或驱动程序管理器的版本号。大多数 DBMS 都带有 ODBC 3.x 驱动程序。
绑定数据库客户端
如果连接数据库需要客户端库,那就必须安装一下。不仅要在编程的计算机上安装,还要在所有运行应用程序的计算机上安装。请注意,某些数据库(特别是 MySQL)要求,编译时绑定的库版本必须与安装运行时的相同。在数据库开发方网站上,可以找到客户端库的安装方法(在 *nix 系统上是 .so 文件,在 Windows 上是 .dll 文件)。有关绑定的代码文件位于 fpc-sources 的 packages/base 目录中。内容基本就是一些客户端 API 的调用,比如 mysql_connect_database,每种数据库的调用各不相同。当然可以用这些代码文件编写数据库应用,但通常会增加很多工作量,且更容易出错,相比之下,使用 Lazarus 的 DB 组件会更为方便。
这些绑定软件包大多用硬编码链接客户端库。这意味着,如果在编译时包含了某个单元,但没有合适的客户端库,那么整个应用程序将无法链接。也就是说,如果计算机中没有安装 MySQL 客户端,程序中又使用了 mysql4.pp 单元,那么将无法生成可执行文件。虽然在安装了 MySQL 客户端库的计算机上编译成功,但在没有对应 MySQL 客户端库的其他机器上该程序仍然无法启动。换句话说:这些数据库要在开发机器上安装客户端库,并且还要将这些客户端库与应用程序一起安装。
为了避免这类问题,有些包能够动态链接到客户端库。在调用客户端库之前,必须先进行“初始化”。如果计算机上没有安装数据库客户端,初始化就会失败。如果客户端库连接就绪,那么之后需要执行“释放”操作。
数据集
数据集和数据库的区别
许多数据库编程新人无法区分数据集和数据库。现在数据库有很多种,比如 Firebird、Interbase、Oracle、Sybase、Microsoft Access 等。
最简单的概念就是,Lazarus 数据集(TDataset 的子类,如 TSQLQuery 等)可视为部分数据库查询记录的副本。假设用以下 SQL 语句打开查询:
SQLQuery1.SQL.Text:= 'select * from table1 where id <=100';
打开 SQLQuery1,数据库 table1 中 id 小于等于 100 的记录将复制到 SQLQuery1 中。
通过 TDatasource(其又与 TDataset 连接),数据集中的数据可用数据库控件(如 TDBGrid、TDBEdit 等)进行可视化展示。
数据集中的数据可通过 insert、edit、delete、post 等命令(后续会讲解)进行修改,但这些操作都是基于数据集进行的,而不是直接在数据库表上完成。需要多做一步才能让改动持久性地存入数据库,比如调用 TDataSet.ApplyUpdates 或执行插入、更新 SQL 语句(与 TDataset.insert 或 TDataset.update 不同)。
通过设置数据库的事务属性,可在数据集关闭时将改动自动保存(或丢弃)。
数据集简介
在 Lazarus(或 Free Pascal)中,数据库的使用底层都基于 TDataSet 类展开。在应用程序中,TDataSet 类代表一张表或一个查询。然而,与很多其他基础类一样,TDataset 类不会直接用到,而会采用其某个子类。这些子类有很多,提供了对各种数据库的访问,例如本地 dBase 或文本文件,或者远程数据库如 PostgreSQL、Firebird、MySQL等。有些子类直接链接到数据库表,而另一些则使用其他组件或库来执行链接。
Dataset 的子类是非可视化组件,通常属于自由组件库(FCL)而不是 Lazarus 组件库(LCL)。
数据集既可通过纯代码方式使用,也可与可视化控件一起使用。典型的 Lazarus 数据库应用通常会同时使用这两种方式。不论哪种方式,第一步都是创建 TDataset 子类,进行初始化以连接到所需的表或查询,并执行 open 操作。可在运行时用代码完成,也可通过在窗体上放置组件并在设计时设置属性来完成。不同的 TDataset 子类在这方面的细节差异很大,因此请参阅数据库中的各个手册,了解操作步骤。
数据集打开后,会创建一些字段组件,每个字段(或打开的表、查询的列)都对应一个字段组件。每个字段组件都是 TField 的子类,根据字段的数据类型(如 TStringField)对应某个子类。
通过代码使用数据集对象
关于以编程方式访问数据集对象的详细说明,请参阅数据集和字段组件的用法,不过以下给出了非常简单的描述:
- 用 TDataset 的子类打开表或查询,过滤出需查看的行,并在各行之间移动。
- 用 TField 的子类:
- 访问字段的定义信息
- 访问当前行的字段值(通过 AsString、AsInteger 之类的属性)
- 用以下方式访问 TDataset 子类的多个字段:
- Fields 属性,如 Fields[0] 是第一个字段
- FieldByName 方法,如 FieldByName('AGE') 返回数据库字段名为“AGE”的字段对象
字段类型的清单参见 Database_field_type。
可视化(数据感知)控件的用法
若要在简单的“RAD”风格的 Lazarus 应用中使用数据库,通常会在设计时配置数据集子类,然后使用数据感知控件。这需要:
- 在窗体中加入所选数据库的数据集子类及支撑组件,并打开(将“Active”属性设为true)。
- 在窗体中加入一个TDataSource组件(位于Data Access 页),并“链接”至数据集组件(设置 DataSet属性)。
- 在窗体中加入数据感知控件(位于Data Controls 页,全都要链接至 DataSource 组件(不是数据集组件)。
- 大多数数据感知控件都是要链接到某个字段的,因此还需设置其 Field 属性。
更多有关控件的信息,请参阅下文中的 #Data Controls。
数据集的状态
数据集可能处于多个状态。状态虽有很多(可以在源代码中查找 TDataSetState),但初学者需要了解的状态主要有:
状态 | 功能 |
---|---|
dsInactive | 已关闭 |
dsBrowse | 用户可浏览,查看数据值 |
dsEdit | 用户可编辑当前行的数据值。在执行 post 前不会保存。 |
dsInsert | 加入新行,用户可设置值。在执行 post 前此行不会保存。 |
其他状态相对短暂,并且通常会“自动”处理,用于内部和更复杂的代码。如果只是查看数据库中的数据,并且在设计时打开数据集,那么很大程度上可以忽略状态的概念,因为大部分时间都会处于 dsBrowse 状态。不过大多数应用都需要修改数据。如果采用数据感知控件,则很多操作都会自动处理。例如TDBEdit控件在修改文本时,会将数据集置于 dsEdit 状态——除非原来就已处于 dsEdit 或 dsInsert 状态。如果在 dsEdit 或 dsInsert 状态时“滚动”到其他记录去,那么当前编辑的记录将被“提交”,数据集将回到 dsBrowse 状态。但如果是用代码访问数据集,那通常就必须用代码修改状态了。TDBNavigator控件(见下文)允许用户显式修改状态。
数据集的 UpdateStatus 属性
如果更新操作尚未写入数据库,UpdateStatus 标识了数据记录缓冲区的当前状态。
示例 如何检测 ApplyUpdates 要执行插入、更新还是删除操作:
procedure QueryAfterPost(DataSet: TDataSet);
begin
case DataSet.UpdateStatus of
usUnmodified : ShowMessage('Unmodified');
usModified : ShowMessage('Modified');
usInserted : ShowMessage('Inserted');
usDeleted : ShowMessage('Deleted');
end;
end;
- 解释
- usUnmodified: 记录未修改
- usModified: 数据库中存在记录,本地已修改
- usInserted: 数据库中不存在记录,本地已插入
- usDeleted: 数据库中存在记录,本地已删除
提交和撤销
如果记录已完成编辑和插入,新值将保存在缓冲区中。
- 调用数据集对象的 cancel 方法,将会删除新记录(插入操作时)或恢复原值(编辑操作时)。
- 调用数据集对象的 post 方法,将会保存记录值(编辑操作时)或新记录(插入操作时)。 有些数据集子类会立即写入数据库,而另一些则会先存入更新列表中,后续再调用某个操作一次性写入数据库。最后,即便数据已经写入数据库,可能仍需调用“commit”方法让数据库执行持久性保存。所有这些操作,都因数据集子类的不同而有很大差异,因此请查看详细的文档。
插入新记录
要通过 TDataSet 子类插入新记录,应该使用 Insert 方法。先要设置字段值,最后再调用 Post 提交新记录,如下所示。
以下例子还展示了如何将文件数据插入 BLOB,也可以用 LoadFromStream 从流中加载数据。
MyDataset.Insert;
MyDataset.Fields[0].AsInteger := 4; //整数字段
MyDataset.Fields[1].AsString := 'First Name'; //字符串字段
(MyDataset.Fields[2] as TBlobField).LoadFromFile('SomeBlobfile.bin'); //blob 字段
MyDataset.Post;
快速跳转至表中某条记录
已查出所有记录
如果是用 SELECT * FROM 查出了表中所有记录,然后要在记录之间快速跳转,那么就得先建索引再检索。更高效的做法是只查询需要的记录。
只查询所需记录
跳转至某条记录的一种做法,就是只查询这条记录,例如:
var
MyDataset: TSQLQuery;
begin
//...
MyDataset.FieldDefs.Add('SessionId', ftLargeint);
MyDataset.FieldDefs.Add('GameEvent', ftLargeint);
MyDataset.FieldDefs.Add('TableId', ftInteger);
MyDataset.FieldDefs.Add('LoggedIn', ftBoolean);
MyDataset.FieldDefs.Add('PlayerId', ftInteger);
MyDataset.Active := False;
{ Non-parameterized format; may run into issues with text containing ' and dates
SQLText := Format('select * from "GameSession" WHERE "SessionId"=%d', [ASessionId]);
}
// 解决方案:带参数的查询
// 如果是在循环中,其实 SQL.Text 只需设置一次,后续只要修改参数值即可。
MyDataset.SQL.Text := 'select * from "GameSession" WHERE "SessionID"=:SessionID');
MyDataSet.ParamByName('SessionID').AsLargeInt := ASessionID;
try
MyDataset.Active := True;
except
//...
end;
然后可以读取数据如下:
lPlayerId := MyDataset.Fields[4].AsInteger;
数据过滤
过滤操作可将数据集限制为所需子集(比如所有以 Smith 开头的姓氏)。
- 使用 .Filter:
- TDbf、TBufDataset 及其子类(包括 TSQLQuery)使用 TDBF 过滤语法,用法详见 Lazarus Tdbf 使用教程。
- TMemDataset 不支持 .Filter。
- 用 OnFilter 回调/事件处理函数,可编写自己的过滤函数。
locate/lookup 方法
locate/lookup 可用于在记录之间跳转,但更多是在非SQL数据集中使用(如TParadoxDataSet、TDbf)。
TSQLQuery 用法
TSQLQuery 详见 Working With TSQLQuery。
数据导出
FPC/Lazarus 提供了将数据集以多种格式导出的工具包:
- fpXMLXSDExport
- fpdbfexport
- Data Export 页上的其他组件
当然,也可以手动导出(比如用 fpspreadsheet 导出为 Excel 格式的 FPSpreadsheet#Converting_a_database_to_a_spreadsheet)。
Data Controls 控件组
使用这些控件需先加到窗体中,并至少应设置 datasource 属性。下面会介绍其他的关键属性。
Datasource 控件
此控件用于跟踪所关联控件当前位于哪条记录。Datasource 控件必须关联某个数据集控件(如 TSQLQuery)。
单字段控件
这些控件都是用于关联单个字段。除了设置 Datasource 外,还需设置字段名称。包括了:
- DBText 控件 显示文本字段(只读,无边框)。
- DBEdit 控件 以文本框的形式显示/编辑文本字段。
- DBMemo 控件 以多行文本框的形式显示/编辑文本字段。
- DBImage 控件 显示以 BLOB 格式存于数据库中的图片。注意:Lazarus 在将图像数据存入数据库的 BLOB 字段时,默认会写入包含图像类型的头部信息。这与 Delphi 不同。但可以让 TDBImage 兼容 Delphi,参见Delphi 用户的 Lazarus 指南。
- DBListBox 控件 和 DBComboBox 控件 允许用户从其 Items 属性值列表中选取数据并插入数据库字段。
- DBLookupListBox 控件 和 DBLookupComboBox 控件,参见 TDBLookupComboBox 通过显示由另一张表字段查出的数据,允许用户从中选取值插入数据库字段中。尽管这些控件将结果存于单个字段中,但需要用到其他字段存放要查找的数据。注:至少 FPC 2.6.0 的 DBLookupComboBox 存在一个 bug,要求 listfield 也必须同在 Datasource 中。只要在 Datasource 的数据集中声明一个与 listfield 同名但不执行操作的计算字段,即可绕过这个问题。
- DBCheckBox 控件 以选中/清除勾选框的形式显示/编辑 boolean 字段。
- DBRadioGroup 控件 以单选按钮组的形式显示多项数据,由匹配上的某项数据读取/设置字段值。
- DBCalendar 控件 以日历面板的形式显示/编辑日期字段。
- DBGroupBox 控件
DBGrid 控件
此控件以行/列布局的形式显示多个字段——其实默认显示所有字段。但可在列集合中添加字段项,以便仅显示指定字段并设置列宽和标题。
除 DBGrid 文档 之外,Grids Reference Page#TCustomDBGrid 也包含更多信息。
此控件能让用户更直接地控制数据集。可以:
- 移至下一条、上一条、第一条或最后一条记录。
- 加入新记录(等效于调用数据集的 insert 方法)。
- 将数据集设为 edit 模式。
- 删除一条记录。
- 提交或撤销当前改动。
- 刷新数据(多用户数据库应用会比较有用)。
主要属性:
- VisibleButtons:控制用户能够执行的操作。假定不允许删除,就可隐藏删除按钮。如果已有 DBGrid 连了同一个数据集,可能需要控制“下一条”和“上一条”按钮是否启用。
- Width:如果所有按钮都不用显示,可能需要设置控件宽度。
FPC 数据库应用的测试
Free Pascal 数据库组件包含了一个基于 fpcunit 的代码测试框架 dbtestframework,可用于验证代码的功能是否正常。 参见 FPC 源码目录 source\packages\fcl-db\tests\。 Included 是个可运行各种数据库组件的测试框架,还包含了一些其他测试(比如数据库输出)。
请按以下步骤配置数据库并运行测试框架:
1. 将 source\packages\fcl-db\tests\database.ini.txt 保存为 source\packages\fcl-db\tests\database.ini
2. 修改 source\packages\fcl-db\tests\database.ini ,选取所需的数据库类型。
连接 Interbase/Firebird 数据库的示例:
[Database]
type=interbase
3. 在同一个文件中配置数据库参数。比如上面选的 Interbase:
[interbase]
connector=sql
connectorparams=interbase
; Database name/path (note: database needs to exist already)
; You can use aliases (see aliases.conf in your Firebird documentation)
name=testdb
user=sysdba
password=masterkey
; your hostname may very well differ:
; Leave blank if you want to use an embedded Firebird database
hostname=192.168.0.42
4. 编译运行 source\packages\fcl-db\tests\dbtestframework.pas (也可用 Lazarus 编译运行 GUI 版的代码 dbtestframework_gui) 若是在 Windows 中使用嵌入式数据库(如 Firebird 嵌入版或 sqlite),请先将所需的 DLL 文件复制到程序所在目录中。输出结果是 XML 格式(dbtestframework_gui 则会显示在屏幕上)。
更多详情请参阅 source\packages\fcl-db\tests\README.txt。
Lazarus 提供的数据库软件包
sqldblaz.lpk
用于访问多种数据库,包括:
- Interbase/Firebird
- Microsoft SQL Server(Lazarus/FPC x64 Windows 版除外)
- MySQL
- Oracle(Lazarus/FPC x64 Windows 版除外)
- PostgreSQL(Lazarus/FPC x64 Windows 版除外)
- SQLite(支持 Spatialite 扩展)
- Sybase ASE(Adaptive Server Enterprise,请勿与 Sybase ASA 混淆)(Lazarus/FPC x64 Windows 版除外)
- 带 ODBC 驱动的所有数据库
所有组件(TSQLQuery、TSQLTransaction、TIBConnection、TODBCConnection、TOracleConnection、TMSSQLConnection、TMySQL40Connection、TMySQL41Connection、TMySQL50Connection、TPQConnection、TSybaseConnection)均位于组件面板的 SQLdb 页。
dbflaz.lpk
用于访问 dBase 和 FoxPro 数据库。详见 Lazarus Tdbf 教程。TDbf 组件位于组件面板的 Data Access 页。
sqlitelaz.lpk
用于访问 SQLite 数据库。详见 Lazarus 数据库开发概述。
sdflaz.lpk
TSdfDataSet 位于组件面板的 Data Access 页。
lazreport.lpk
报告生成器的项目主页位于 http://lazreport.sourceforge.net/。 更多信息(其他链接)详见 这里。 LazReport 依赖 Printer4Lazarus 包。 Lazarus SVN 仓库纳入了 LazReport 11950 修订版。
lazdbexport.lpk
参见 lazdbexport。
外部软件包/库
Zeos DataBase Objects
这些组件用于访问各种数据库。更多信息请参阅此处,自带 Zeos 教程。
Pascal Data Objects
已有替代品。
支持:
- MySQL 4.1 和 5.0
- sqlite-2 和 sqlite-3
- pgsql-8.1
- interbase-5、interbase-6、firebird-1.0、firebird-1.5、firebird-1.5E、firebird-2.0、firebird-2.0E
- mssql(Microsoft 库)和 sybase(FreeTDS 库)
- oracle
数据库 API Pascal Data Objects 支持预编译语句、绑定和存储过程等功能,设计灵感来自 PHP Data Objects。所有代码和文档均在 Sourceforge: http://pdo.sourceforge.net
TPSQL
通过 TCP/IP 访问 PostgreSQL 数据库。详见 TPSQL。
FIBL
用于访问 Interbase 和 Firebird 数据库。主页为 [3]。
IBX
用于访问 Firebird 数据库,参见IBX。
FBLib Firebird Library
FBLib 是个开源库,无数据感知能力,用于 Borland Delphi/Kylix、Free Pascal 和 Lazarus 直接访问 Firebird 关系数据库。
目前支持以下特性:
- 直接访问 Firebird 1.0.x、1.5.x、2.x Classic 或 SuperServer
- 跨平台 [Win32、Gnu/Linux、FreeBSD)
- 自动选取 fbclient 或 gds32 客户端库
- 带参数查询语句
- 支持 SQL Dialect 1/3
- LGPL 授权协议
- 读取元数据
- 简单的脚本解析
- 最终 EXE 文件大小只增加 100-150 KB
- 支持 BLOB 字段类型
- 数据导出为 HTML SQL 脚本
- 服务管理程序(备份、恢复、gfix 等)
- 事件告警
文档见 FBLib 网站。
Unified Interbase
UIB 支持访问 Interbase、Firebird 和 YAFFIL 数据库。主页为 www.progdigy.com。svn 仓库 https://uib.svn.sourceforge.net/svnroot/uib。
TechInsite Object 持久化框架 (tiOPF)
详见 tiOPF。
访问 Advantage 的 TDataSet 子类
Advantage TDataSet 子类可用于连接 Advantage 数据库服务器(访问表)。Advantage 是一种灵活的、无需管理的嵌入式数据库,支持客户端/服务器或点对点方式访问 Clipper、FoxPro 和 Visual FoxPro 9 的 DBF 文件格式,同时还支持一种专有文件格式并提供迁移方案,以便用户能应用新特性。
主要特性:
- 支持免费由点对点方式迁移至客户端/服务器模式。
- 跨平台(客户端支持 Windows 和 Linux,服务器端支持 Windows、Linux 和 NetWare)。
- 同时支持支持导航式访问和关系型 SQL 数据库式访问。
- 全文本搜索引擎。
- 表、索引、Memo 和通讯加密。
- 与原生 TDataset 组件兼容。
- 在线备份
- 支持复制的数据库服务器
更多信息,请参阅网站 Advantage Database Server。
ZMSQL:增强型 SQL 内存数据库
更多信息,请参阅 ZMSQL wiki。
ZMSQL 是开源的、基于 TBufDataset 子类的增强型 SQL 内存数据库,专为 Free Pascal(FPC)设计,基于分号分隔的文本表进行操作。ZMSQL 完全用 Pascal 语言编写,不依赖任何外部库,SQL 功能用 JanSQL 引擎实现。
支持以下特性:
- 文本表的加载/保存
- 用 SQL 查询数据
- 从其他数据集复制数据和模式
- 字段定义可选择预定义或即时创建
- 主/从表过滤
- 参照完整性
- 参数化查询
可下载的内容包括了源代码、演示应用(用于说明组件的功能)和自述文件。