维基副本镜像

这是 pascal.chat 维基的镜像。编辑、历史记录和登录都在那里。

SQLite/zh CN

English · Español · Français · Polski · Русский · 中文(中国) · 日本語

SQLite 和 FPC/Lazarus 支持

SQLite 是一个嵌入式的 (非服务器的) 、单用户的、可以在 FPC 和 Lazarus 应用程序中使用的数据库。许多驱动可以用于在FPC/Lazarus程序中访问SQLite数据库。 所有的驱动都需要SQLite库/dll在可执行目录(可以是你的项目目录,或者例如 (projectdir)/lib/architecture/ ,这取决于你的Lazarus项目设置)(并与你的可执行文件一起发行)以正常运作。

这可能也需要悲包含在你的 Lazarus IDE 目录. 详见 1 并继续阅读 TSQLite3Dataset 和 TSQLiteDataset See below

大多数 Linux发行版默认安装有 sqlite3 (例如 libsqlite3.so.0),但至少基于Debian的发行版也需要匹配的Dev包才能获得 libsqlite3.so。两者都应通过系统包管理器安装并标记为依赖项,而不是与应用程序一起分发。

Win64: 请看 这里 关于不使用某些 FPC/Lazarus Win64 版本的警告

直接访问 SQLite

你可以使用一种简单的方式在 Lazarus 上连接到 SQLite。名为 LiteDAC 的组件。SQLite 数据访问组件(LiteDAC)是一个提供原生的SQLite连接的组件库,在 Windows, macOS, iOS, Android, Linux 和 FreeBSD 的32位及64位上的的Lazarus(和 Free Pascal)。LiteDAC 为编程者开发真正跨平台的桌面和移动的 SQLite 数据库应用程序而无需部署其它额外的库而设计。

你可以在这里下载一份这个商业产品的适用版本 Lazarus components.

内建的 SQLDB

FPC/Lazarus 提供内建的 SQLDB 组件,它提供 SQLite 数据库 (TSQLite3Connection) 从 Component Palette 的 SQLdb tab,它允许你例如使用形如 Component Palette 的数据库组件来创建图形界面。使用 SQLDB 的有点是它可以很容易地更换到一个不同的数据库例如 FireBird 或 PostgreSQL,而不必太多修改你的程序。详情请见下文。

Spatialite support

Spatialite are GIS extensions to SQLite which you can use from within SQLDB. See Spatialite.

SQLite 加密的支持

在近期的 FPC 版本 (从 FPC 3.0.0 开始, 在 2012年3月 实现), SQLDB 包括了对 SQLite3 的某些扩展版本的支持,这些版本使用 AES 算法加密 SQLite 数据库文件。 使用“Password”属性设置加密密钥。

示例:

根据您使用的内容,可能还需要在“5.0 C interface”处单独启用加密如此处所写, 在访问加密数据库之前,您需要使用产品密钥调用 sqlite3_activate_see() 。

sqlite3backup

sqlite3backup 是 FPC 提供的一个单元(不在 Lazarus 中,但可以通过编程方式使用),为 SQLite3 提供备份/恢复功能。 它使用 SQLDB 的 sqlite3conn。

Zeos

Zeos

SQLitePass

SQLitePass 组件. 2010年最后一次编码. 上次社区活跃在2011年.

TSQLite3Dataset 和 TSQLiteDataset

还有单独的TSQLiteDataset(单元 sqlites)和TSQLite3Dataset(单元 sqlite3ds)包; 有关如何使用它们的说明,请参阅下文。 访问 sqlite4fpc 主页 查找 API 参考和更多教程。

TSqliteDataset 和 TSqlite3Dataset 是 TDataSet 后代,分别访问 2.8.x 和 3.x.x sqlite 数据库。 对于新项目,您可能会使用 TSQlite3Dataset,因为 SQLite 3.x 是当前版本。

下面列出了与其他 FPC/Lazarus SQLite 驱动程序/访问方法相比的主要优点和缺点:

优点:

缺点:

Note: 鉴于上述情况,许多用户会因为 SQLDB 或 Zeos 的优点而使用 SQLDB 或 Zeos,除非他们需要对 SQLite 库进行较低级别的访问

使用SQLdb组件以使用SQLite

这些说明重点关注 SQLite 的 SQLDB (TSQLite3Connection) 细节。 有关一般概述,请查看 SqlDBHowto,其中包含有关 SQLdb 组件的一些有用信息。

有关创建为 SQLite/SQLDB(以及 Firebird/SQLDB、PostgreSQL/SQLDB,基本上任何 RDBMS SQLDB 支持)编写的支持 GUI 数据库的程序的教程,请参阅 SQLdb Tutorial1。

我们将使用 Lazarus SQLdb 选项卡中的三个组件的组合:TSQLite3Connection、TSQLTransaction 和 TSQLQuery。 TSQLQuery 充当我们的 TDataset; 在最简单的情况下,它仅代表我们的一张表。 为了简单起见:确保您已经拥有一个现有的 SQLite 数据库文件,并且现在不需要创建新的文件。 如果您想自己声明或者在 FreePascal 中工作,TSQLite3Connection 可以在“sqlite3conn”单元中找到。

这三个组件像平常一样相互连接:在 TSQLQuery 中设置属性 Database 和 Transaction,在 TSQLTransaction 中设置属性 Database。 Transaction 和 Connection 组件中没有太多可做的事情,大部分有趣的事情将在 TSQLQuery 中完成。 配置组件如下:

TSQLite3Connection:

注意:要设置完整的库路径(如果您将 sqlite dll/so/dylib 放置在操作系统找不到它的地方,例如 Linux/OSX 上的应用程序目录),您可以设置 SQLiteLibraryName 属性(在建立任何连接之前,例如在主窗体的 OnCreate 事件中),如下所示:

pascal
SQLiteLibraryName:='./sqlite3.so';

TSQLQuery:

正确设置上述所有内容后,您现在应该能够像任何其他 TDataset 一样使用 TSQLQuery,方法是通过以编程方式操作其数据,或者将 TDatasouce 放置在表单上,将其连接到 TSQLQuery,然后使用 TDBGrid 等数据控件。

创建一个数据库

从父类继承的TSQLite3Connection.CreateDB方法实际上什么也不做; 要在尚不存在文件的情况下创建数据库,您只需编写表数据,如下例所示:

(从 Lazarus 1.3 及以上版本附带的 sqlite_encryption_pragma 示例中提取的代码)

pascal
var
  newFile : Boolean;
begin

  SQLite3Connection1.Close; // 确保启动时连接已关闭

  try
    // 由于我们是第一次创建这个数据库,
    // 检查文件是否已经存在
    newFile := not FileExists(SQLite3Connection1.DatabaseName);

    if newFile then
    begin
      // 创建数据库和表
      try
        SQLite3Connection1.Open;
        SQLTransaction1.Active := true;

        // 这里我们在新数据库中设置一个名为“DATA”的表
        SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
                    ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
                    ' "Current_Time" DateTime NOT NULL,'+
                    ' "User_Name" Char(128) NOT NULL,'+
                    ' "Info" Char(128) NOT NULL);');

        // 根据DATA表中的id创建索引
        SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');

        SQLTransaction1.Commit;

        ShowMessage('Succesfully created database.');
      except
        ShowMessage('Unable to Create new Database');
      end;
    end;
  except
    ShowMessage('Unable to check if database file exists');
  end;
 end;

创建用户定义的排序规则

pascal
// utf8 区分大小写的比较回调函数
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
  SetString(S1, data1, len1);
  SetString(S2, data2, len2);
  Result := UnicodeCompareStr(UTF8Decode(S1), UTF8Decode(S2));
end;

// utf8 不区分大小写的比较回调函数
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
  SetString(S1, data1, len1);
  SetString(S2, data2, len2);
  Result := UnicodeCompareText(UTF8Decode(S1), UTF8Decode(S2));
end;

// 使用 SQLite3 API 注册排序规则(需要 sqlite3dyn 单元):
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// 或使用 TSQLite3Connection 的方法:
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);  

// 现在我们可以在 SQL 中使用不区分大小写的比较,例如:
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'

// 但这对于 LIKE 运算符不起作用
// 为了也支持 LIKE 运算符,我们必须使用 sqlite3_create_function() 重载默认的 LIKE 函数
// http://www.sqlite.org/lang_corefunc.html#like

创建用户定义的函数

pascal
// 使用用户提供的函数重载默认 LOWER() 函数的示例
// 要运行此演示,您必须将单元'sqlite3dyn'和'ctypes'添加到您的uses-clause中
// 并添加一个值为 $800 的 const 'SQLITE_DETERMINISTIC'

procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
var S: AnsiString;
begin
  SetString(S, sqlite3_value_text(V[0]), sqlite3_value_bytes(V[0]));
  S := UTF8Encode(AnsiLowerCase(UTF8Decode(S)));
  sqlite3_result_text(ctx, PAnsiChar(S), Length(S), sqlite3_destructor_type(SQLITE_TRANSIENT));
end;

// 注册函数 LOWER() 使用 SQLite3 API (requires sqlite3dyn unit):
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);

SQLite3 与日期

http://www.sqlite.org/datatype3.html#datetime。

默认值采用当地时间而不是 UTC

CURRENT_TIME、CURRENT_DATE 和 CURRENT_TIMESTAMP 返回当前 UTC 日期和/或时间。 对于本地日期和/或时间,我们可以使用:

text
  DEFAULT (datetime('now','localtime')) 对于格式为 YYYY-MM-DD HH:MM:SS 的日期时间值
  DEFAULT (date('now','localtime')) 对于格式为 YYYY-MM-DD 的日期值
  DEFAULT (time('now','localtime')) 格式为 HH:MM:SS 的时间值

SQLDB 和 SQLite 故障排除

pascal
interface
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);overload;
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);overload;  
 
implementation
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
//此过程刷新数据集并将光标定位到最后一条记录
//如果数据集不能保证按自动增量主键排序,则使用
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  //获取数据库中最后插入的ID
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  //Now come back to respective row
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //刷新并返回相应行
    pDataset.Locate(pKeyField,vLastID,[]);
  end;
end;
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
//此过程刷新数据集并将光标定位到最后一条记录
//仅在保证DataSet按自动增量主键排序时使用
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //危
    pDataSet.Last;
  end;
end;

procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery); //如果你的数据集是按主键排序的
end;  

procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //如果你不确定数据集总是按主键排序
end;

真空和其他必须在事务外完成的操作

SQLDB 似乎总是需要connection,但某些操作(例如 Pragma 和 Vacuum)必须在transaction之外完成。 诀窍是结束transaction,执行你必须做的事情然后在此开始transaction(这样sqldb就不会混淆:)

pascal
  // 提交任何挂起的操作或使用“新”sql连接
  Conn.ExecuteDirect('End Transaction');  // 结束由 SQLdb 启动的transaction
  Conn.ExecuteDirect('Vacuum');
  Conn.ExecuteDirect('Begin Transaction'); // 启动一个transaction供 SQLdb 使用

使用 TSQLite3Dataset

本节详细介绍如何使用 TSQLite2Dataset 和 TSQLite3Dataset 组件访问 SQlite 数据库。 by Luiz Américo luizmed(at)oi(dot)com(dot)br

要求

在初始化一个Lazarus项目之前, 确保:

怎样使用 (基础用法)

安装在 /components/sqlite 目录中找到的包 (见说明: here)

在设计时,设置以下属性:

创建表 (Dataset)

双击组件图标或使用单击鼠标右键时出现的弹出菜单中的“创建表”项。 将显示一个简单的不言自明的表格编辑器。

以下是 TSqliteDataset 和 TSqlite3Dataset 支持的所有字段类型:

检索数据

创建表后或使用之前创建的表,使用 Open 方法打开数据集。 如果未设置 SQL 属性,则将检索所有字段中的所有记录,如果将 SQL 设置为:

pascal
SQL := 'Select * from TABLENAME';

将更改应用到基础数据文件

要使用ApplyUpdates函数,数据集必须至少包含一个满足主键要求的字段(值必须是UNIQUE且不为NULL)

可以通过两种方式做到这一点:

如果设置了两个条件之一,则只需调用

pascal
ApplyUpdates;

Note: 如果两个条件都设置了,则使用 PrimaryKey 对应的字段来应用更新。

Note: 将PrimaryKey设置为非主键的字段,如果调用ApplyUpdates,将导致数据丢失,因此在使用之前请确保所选字段不包含Null和Unique值。

大纲/详细信息示例

主/详细关系的各种示例(例如客户和订单之间的关系):

评论

通用示例可以在 fpc/fcl-db/src/sqlite SVN 目录中找到

也可以看看


From the Free Pascal wiki, page "SQLite/zh CN", as it stood on 2023-07-15 after a change by Iruanp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

版本3,最后由WikiArchive于修改。