数据库中Post、ApplyUpdates和Commit有什么区别?

10

我正在努力理解在更改数据库后要使用的命令。我是通过SQLite3和db-aware控件学习的,这是我的理解...

当用户在db-aware控件中输入内容(或以其他方式将内存数据集置于编辑状态)时,POST会将更改存储在内存中。控件通常会自动或隐式地为您执行此操作。

尽管必须在任何更改被识别之前进行提交,但更改尚未发送到实际的磁盘数据库文件中。它们只存在于内存中。将更改发送到磁盘需要APPLYUPDATES

即使通过APPLYUDATES将更改发送到磁盘上的文件,它们仍然可以被更改或回滚。就像点击撤消一样。在调用COMMIT之前,它们不会永久保存到磁盘上。

这听起来正确吗?我真的很想知道我在做什么,所以我不只是复制和粘贴代码。但请随意复制、粘贴和编辑我的回答。


您在 Delphi 代码中可能不需要调用 Commit。服务器连接可能(默认配置)将提交到服务器的更改封装在隐式事务中。对于没有真正服务器,只有 DLL 的 SQLite,它可能取决于您使用的 TDataSet 后代组件 - 检查其文档或源代码。 - MartynA
2个回答

15

你的问题的答案是,PostApplyUpdatesCommit完全不同,并且通常在数据库应用程序中发生在不同的位置(进程)和上下文中。

PostApplyUpdates都是客户端操作,而Commit是一个SQL操作,可能需要在服务器端显式调用以完成事务。

如果考虑一个三层服务器,就能更容易地理解它们之间的区别。SQLite有点奇怪,因为它不是真正意义上的Sql Server,不能像设计用于响应来自不同机器上不同进程的调用的服务器那样使用(尽管它可以作为三层系统的后端进行这样的操作)。

最简单的传统三层架构通常是这样的:中间层Delphi服务器位于Sql Server(例如MS Sql Server)和客户端层之间,客户端层通常是在客户机上运行的Delphi程序。Borland/EMBA实现这一点的传统技术是DataSnap

客户端层通常包含一个TClientDataSet(或第三方等效组件),通过中间层中与服务器特定的TDataSet派生类从后端SQL服务器接收数据。虽然将数据从Sql Server传输到中间层通常涉及Sql Server上的事务,但一旦所有数据都加载到客户端层的CDS中,SQL Server上就没有挂起的事务了(除非您想要在服务器上保持事务打开状态,这不友好于服务器的其他用户,并且会消耗服务器上的锁资源,这是有限的)。

当您编辑CDS中的数据(或任何TDataset派生类,实际上),会将数据集置于dsEdit状态(请参阅TDataSetState的在线帮助)。所做的更改是暂时性的,这意味着它们可以在CDS中撤消,直到调用.Post保存它们到CDS的Data(对于TClientDataSet,在调用.ApplyUpdates之前,可回滚对客户端数据的更改)。请记住,在客户端层上调用.CDS时,Sql Server中没有挂起的事务(或至少不应该有)。

调用.Post不会导致更改传播回相应的中间层数据集。要启动此过程,请在客户端层CDS上调用ApplyUpdates,它会涟漪到与中间层的面向服务器的数据集接口的TDataSetProvider中。正是DataSetProvider(或更准确地说是与其关联的TSqlResolver)生成实际发送到SQL服务器以将更改应用于SQL数据库的SQL。因此,在标准的DataSnap 3层设置中,您无法直接控制是否调用Commit。

Commit是Sql Server执行的SQL操作,是完成事务的两种可能方式之一(另一种是Rollback)。例如,对于MS Sql Server,连接到服务器可能配置为自动将接收到的UPDATEINSERTDELETE语句包装在隐式事务中。

您需要关注事务控制的程度取决于您正在使用的后端服务器以及应用程序对与其他使用服务器数据的并发性的要求。如果您对SLite的事务处理感兴趣,请查阅您使用的DBcomponents或其源代码的文档。

一些用于与真正的SQL服务器一起工作的Delphi组件库支持公开控制服务器端事务的设施,例如Interbase的IBX组件。

顺便提一下,在Delphi术语中,CachedUpdates是从早已过时的BDE遗留下来的,这是Borland公司最初尝试为各种后端服务器提供通用数据库访问框架的努力。它存在于一些TDataSet派生实现中,并且(在我看来)不幸地在FireDAC中重新出现了,EMBA的最新跨数据库解决方案。


1
感谢您的信息回复。非常有帮助。只是为了跟进一下,如果服务器要求我发送COMMIT命令,您认为应该在ApplyUpdates之前还是之后呢?似乎应该在调用向主服务器发送更新之前编写它。 - Al C
如果你特指向后端服务器发送 SQL COMMIT 语句,那么这必须放在 ApplyUpdates 之后,因为只有在执行 ApplyUpdates 后才会向后端服务器发送必要的 SQL UPDATE 命令,以使得包含在 COMMIT 中的事务所做的更改生效。 - MartynA

-1

当您使用ApplyUpdates时,必须将CachedUpdates属性设置为True。然后,您可以使用post、delete(以及其他操作)来更改数据,这些更改将首先被放入缓存中。在调用ApplyUpdates时,您所做的所有更改都将存储在数据库中。使用CancelUpdates可以撤消您所做的所有更改。当您将CachedUpdates属性设置为false时,您所做的所有更改都将直接存储在数据库中。无法使用ApplyUpdate和CancelUpdates命令。


1
那么,COMMIT 命令是做什么用的? - Al C
使用COMMIT语句来结束当前事务并将在该事务中进行的所有更改永久保存,以保存更改。 - Iresha Rubasinghe
1
谢谢你抽出时间回复我,Iresha。 - Al C
“你必须将CachedUpdates属性设置为True。”很抱歉,这并不是所有情况下都正确的。例如TClientDataSet就没有CachedUpdates属性,如果CDS位于中间层并且通常与TAdoXXX数据集一起在服务器端使用,则也不需要调用Commit,这取决于服务器端的情况。 - MartynA
哦,对不起,这并不适用于所有情况。给您带来的不便深感歉意。 - Iresha Rubasinghe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接