与一般的数据集组件不同,TClientDataSet使用的技术比较特别,本着高速度、低存储需求的原则TClientDataSet的内部使用了两个数据存储源。第一个是其Data属性,这是当前内存数据的视图,反映了所有的数据改变。如果用户从数据中删除一条记录,则此记录将从Data中消失,相应地,加入一条新记录后,此记录便存在Data属性中了。另一个数据源是Delta属性,故名思义,即增量的意思,这个属性反映了对数据的改变。无论是向 Data 属性新增还是删除记录,都会在Delta中记录下来,如果是修改了Data中的记录,则会在 Delta 保存两条相应的记录,一条是原始记录,另一条仅包含修改的字段值。
正因为 Delta 的存在和 TClientDataSet 在内存中记录数据的特点,所有的改变都没有立即更新加对应的物理存储中,可以根据这些信息在适当的时候恢复,所以 TClientDataSet天生具有缓冲更新功能。为了使数据更新回数据存储源,我们要调用TClientDataSet中对应的方法。如果ClientDataSet 与 DataSetProvider关联,那么仅需调用TClientDataSet的ApplyUpdates方法即可保存数据的更新,但如果 TClientDataSet没有对应的TDataSetProvider存在,而是直接同文件关联,那么,这种方式是非常有趣的,我们在 BriefCase模型中会再次讲解这个问题。此时,如果使用TClientDataSet的 SaveToFile 和 LoadFromFile ,都会保留着Delta。调用MergeChangeLogClearChanges后,Delta的内容才会被清空。只是前者是将Delta的数据同Data结合起来,将改变存储到物理介质上,ClearChanges则是一股脑儿全部清空,将数据回复到原始状态。大部分的应用都是将TClientDataSet与TDataSetProvider结合使用的。两者联合使用的行为反映了Borland的设计宗旨,就是要提供一个面向分布式环境的思路。我们下面来慢慢解释。
当我们将TClientDataSet对象的Active属性设为True或者调用其Open方法后,ClientDataSet 会向 DataSetProvider发送一个取数据包请求。于是DataSetProvider 便会打开对应的数据集,将记录指针指向第一条记录,然后从头到尾依次扫描。对于扫描到的每一条记录,都会将其编码成一个 variant 数组,我们通常将它称之为数据包。完成扫描后,DataSetProvider 会关闭指向的数据集,并将所有的这些数据包传递给ClientDataSet。在我提供的演示程序中,你可以清楚地看到这种行为(毕竟眼见为实吗!)。程序主界面右边的DBGrid连接到一个指向数据库表的数据源,DataSetProvider即指向此表。当选择了ClientDataSet | Load菜单项时,你可以看到表格的数据被依次扫描,一旦到达最后一条记录,表格便会被关闭,右边的DBGrid被清空,而左边反映ClientDataSet数据的DBGrid便出显示出内存中的数据来。由于这个过程会在DBGrid上反映出来,所以不到1000条记录的取出时间中,大部分都浪费在屏幕的更新显示上了,你可以选择ClientDataSet | View Table Loading来禁止显示,而达到加速的目的。
在上面的描述中,我们没有提到一个重要的环节,即数据包是如何还原成表格的。那是因为 DataSetProvider 会将数据包中的元数据解码出来,根据元数据(我们可以理解为数据表的结构)便可以构造出与物理数据表一模一样的内存虚拟表。但要注意的是,尽管DataSetProvider指向的数据表可能有多个索引,但这些信息是不会放在数据包中的,换句话说,ClientDataSet当中的数据默认情况下是无索引的。但因为ClientDataSet具有与TDataSet一致的行为,所以我们可以在此基础上根据需要重建索引。
在ClientDataSet中的数据被修改后,可以提交给物理数据表持久化这此改变。这个工作便是由DataSetProvider完成的。内部工作原理是:DataSetProvider创建一个TSQLResolver的实例,这个实例会生成要在底层数据上执行更改的SQL语句。详细地说,就是对修改日志中的每一条被删除、插入、更改记录生成对应的SQL语句。这个语句的生成也可以由用户控制,DataSetProvider的 UpdateMode 属性和ClientDataSet中的ProviderFlags属性都对SQL语句的生成有影响。当然,你也可以换一种方式,即采取同单机或C/S结构一样的数据直接操作机制,绕过SQL语句和缓冲更新机制来修改数据库。只需将 ResolveToDataSet属性设为True,那么DataSetProvider在持久化更新时便不会使用TSQLResolve,而是直接修改物理数据源。即定位到要删除的记录,调用删除语句,定位到修改记录,调用修改语句。我们可以对演示程序稍加修改,观察此种行为。请将演示程序中的 DataSetProvider的ResolveToDataSet属性由False改为True,运行。在界面中修改数据并且保存,你将会看到右边的导航按钮会在瞬间变得可用。
更绝妙的是,Borland考虑到了应用的多样性,为我们提供了BeforeUpdateRecord事件,这样,当DataSetProvider对每个修改日志的记录进行操作时,都会触发此事件,我们可以在此事件中加入自己的处理,如“加密操作”、“商业敏感数据处理”等应用,从而极大地方便了程序员,让程序员对于数据具有完全的控制能力。分布式环境的复杂性对数据的存取提出了更高的要求,所以使用事务来保证数据的完整性和一致性是非常必要的,Borland考虑到了这一点,当调用ClientDataSet的 ApplyUpdates时,你可以传递一个整数值来指明可以容忍的错误数量。如果你的数据非常严格,则可以传递0值,这样,DataSetProvider在应用修改时便会打开一个事务,如果遇到错误,便会回退此事务,修改日志将保持原样,并且将出错的记录标记出来,最后会触发OnReconcileError事件。如果传递了一个大于0的数,则当出现的错误数量小于此指定值时,事务会被提交,发生错误而导致提交失败的记录会保留在Delta中,而提交成功的记录会从修改日志中删除。若错误数量达到指定值,则事务会回退,结果同整数值为0的情况。如果值为负数,则会交所以可提交的数据都提交,不可提交的数据仍然保存在修改日志中,并将出错记录标记出来。
http://hi.baidu.com/f4606304/blog/item/647184afcd372c1f4a36d612.html
分享到:
相关推荐
网上看了一些转的方法都有漏洞下面直接上代码
在Delphi中,我们可以通过定义数据字段、关联字段类型和数据源,使ClientDataSet与XML数据匹配。一旦XML数据被加载到ClientDataSet,就可以进行查询、编辑和过滤等操作。 5. **错误处理和调试**:在实际应用中,...
- 在Delphi中,默认情况下,字符串比较是大小写敏感的。如果在过滤条件中没有正确处理大小写问题,则可能导致过滤结果不准确。 - `ClientDataSet`提供了`FILTEROPTIONS`属性来控制过滤时的行为。其中`...
摘要:Delphi源码,控件组件,ClientDataSet Delphi环境下的ClientDataSet使用例子。ClientDataSet是Delphi三层开发常用控件。通过此例子帮助那些初学者学会ClientDataSet的使用,简单易懂。演示打开本地文件、保存到...
在IT领域,ClientDataSet(CDS)是一种在 Delphi 和 C++Builder 等RAD Studio环境中广泛使用的组件,用于处理离线数据。它允许开发者在应用程序中存储、编辑和过滤数据,而无需直接连接到数据库服务器。在这个...
将ClientDataset的Delta数据打包成JSon字符串 可以将这个JSon字符串传递到服务端, 进行解码,生成更新的SQL语句. 主键更新. 建议主键使用GUID,这样更新数度快, SELECT可以多个表,但是要更新的字段不要AS成其他名字. ...
Delphi 10.3 ,程序运行到DataModule2.ClientDataSet1.ApplyUpdates(0);语句时,提示“Invalid parameter”错误
在Delphi中调用Java接口,主要依赖于JNI提供的机制。首先,我们需要了解JNI的头文件和库文件,它们是Delphi与Java通信的基础。 2. **创建Java接口** 在Java环境中,定义一个公共接口,包含待调用的方法。例如: `...
为了在Delphi中处理JSON数据,开发者通常会依赖第三方库,如本压缩包中提供的"JsonDataObjects.pas"和"superobject.pas"。 "JsonDataObjects.pas"可能是一个基于Delphi 7的JSON库,它提供了一系列类和方法来解析、...
在Delphi中,实现主从表控制通常涉及到以下步骤: 1. **数据模型设计**:在数据库层面,需要定义好主从表的关系,通常是通过外键约束实现。例如,订单详情表有一个订单ID字段,它是订单表的外键。 2. **服务端设置...
### Delphi中ClientDataSet的应用详解 #### 一、概述 `ClientDataSet`是Delphi中一个重要的数据库组件,主要用于客户端应用程序。它从`TDataSet`类派生而来,具有多种特性,使其非常适合于多层架构的开发场景。与`...
Delphi演示如何一次删除网格数据表dbgrid中的多条记录,小技巧不过挺实用,希望对大家的Delphi编程有所帮助。以下是实现一次删除多条记录的相关代码供参考: if DBGrid1.SelectedRows.Count >1 then s:= '真的要...
ClientDataSet(简称CDS)是Delphi数据库编程中的一种重要组件,它是从TDataSet派生出来的,常用于构建多层架构的客户端应用。与TTable和TQuery不同,CDS并不直接依赖BDE(Borland Database Engine),而是依赖于...
1. **DBGrid组件**:DBGrid是Delphi中用于显示和编辑来自数据源(如TClientDataSet)的表格数据的可视化组件。它能够自动根据数据字段的数量和类型创建列,并且支持用户交互,如排序、过滤和编辑。 2. **...
本示例库,"delphi多线程精品示例",提供了关于如何在Delphi中有效地管理和利用多线程的高质量代码。 首先,我们来理解多线程的基本概念。线程是程序执行的最小单位,每个线程都有自己的执行上下文,包括程序计数器...
总结来说,“ClientDataSet XML”项目演示了如何在Delphi中利用ClientDataSet组件和XML技术来构建一个离线账目管理系统。这涉及到XML数据的读取、操作和存储,以及CDS与用户界面组件的交互。这样的系统具有灵活性和...
在 Delphi 开发环境中,内存中的数据修改是一个常见的任务,特别是在处理数据库或其他数据源时。本示例将探讨如何在 Delphi 中直接操作内存中的数据,以实现对数据源的修改。Delphi 提供了丰富的组件库和语言特性,...
本篇将深入探讨如何在Delphi中实现这一功能,主要关注文本文件和数据库记录的处理。 首先,让我们从文本文件开始。在Delphi中,我们可以使用`TStringList`类来读取和处理文本文件。以下是一个简单的示例,演示如何...
Delphi通过WebService访问数据库. 1.查询数据 procedure TForm1.Button1Click(Sender: TObject); var ls_Table: string; ls_Service: Service1Soap; begin ls_Service := Buf_GetBuleService; ls_Table := '...
在 Delphi 开发环境中,FireDAC 是一个强大的数据库访问组件,它支持多种数据库系统,并提供了高效的数据处理能力。本文将详细讲解如何使用 FireDAC 的 Delta 功能来记录操作日志以及如何将 Delta 转换为 SQL 语句,...