对远程视图进行数据修改后发现修改错了,如何恢复修改前的数据?

ZJM4862915 2010-01-15 08:43:23
我用VFP8.0设计的表单表格数据源为SQL数据库远程视图,在该表单中设计了“修改”、“确认修改”、“放弃修改”命令按钮,按“修改”命令,则将表格的readonly属性设置为.F. ;按确认“修改”命令,则使用requery("远程视图名")函数刷新远程视图而保存所修改的数据;但当发现修改错了而要恢复修改前的数据,则应如何设置“放弃修改”命令而使表单表格显示修改前的数据?
另:如果表单表格的数据源为本地dbf表,应如何设置“放弃修改”命令而使表单表格显示修改前的数据?
敬向电脑高手请教,应如何编程,不胜感激!
...全文
152 5 打赏 收藏 举报
写回复
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
十豆三 2010-01-16
  • 打赏
  • 举报
回复
这是放弃修改的例子(均来自VFP自带的帮助文件)

下面的示例指示您如何使用TABLEREVERT( ) 来放弃对被缓冲的表所做的修改。因为缓冲表的原因,MULTILOCKS被置为 ON。打开testdata数据库中的cusstomer表,并通过CURSORSETPROP()函数来将表的缓冲模式改为5-开放式表缓冲。

然后分别显示修改以前cust_id字段值,及通过REPLACE命令修改以后的cust_id字段值。然后调用TABLEREVERT()函数来将表恢复到修改前的状态(TABLEUPDATE()可以将所做的修改提交到数据表)。最后显示放弃修改后的custid字段的值。

CLOSE DATABASES
SET MULTILOCKS ON && Must be on for table buffering
SET PATH TO (HOME(2) + 'data\') && 设置数据库路径
OPEN DATABASE testdata && Open testdata database
USE Customer && 打开临时表
= CURSORSETPROP('Buffering', 5, 'customer') && 能够表缓冲

CLEAR
? 'Original cust_id value: '
?? cust_id && 显示当前的 cust_id 值
REPLACE cust_id WITH '***' && 改变字段内容
? 'New cust_id value: '
?? cust_id && 显示新 cust_id 值
= TABLEREVERT(.T.) && 放弃全部表的更改
? 'Reverted cust_id value: '
?? cust_id && 显示恢复的 cust_id 值

十豆三 2010-01-16
  • 打赏
  • 举报
回复
这是确认修改的例子

下面的示例演示了如何使用TABLEUPDATE( ) 提交修改到一个起用了表缓冲的表。首先创建了一个名称为employees 的数据表,然后通过SQL INSERT 语句插入一条cLastName字段为"Smith"的记录。

由于缓冲表的需要,将MULTILOCKS 置为ON,。然后调用CURSORSETPROP( ) 函数将表的缓冲模式设置为5-开放式表缓冲。

先显示 clastname 字段的初始值 (smith),接着用 replace 命令修改 clastname 字段,然后显示 clastname 字段的新值 (jones),最后用 tableupdate( ) 实施对该表的更改(也可使用 tablerevert( ) 函数实施更改),最后显示 clastname 字段值 (jones)
 
CLOSE DATABASES
CREATE TABLE employee (cLastName C(10))
SET MULTILOCKS ON && Must turn on for table buffering.
= CURSORSETPROP('Buffering', 5, 'employee' ) && Enable table buffering.
INSERT INTO employee (cLastName) VALUES ('Smith')

CLEAR
'Original cLastName value: '
cLastName && Displays current cLastName value (Smith).

REPLACE cLastName WITH 'Jones'
'New cLastName value: '
cLastName && Displays new cLastName value (Jones).

= TABLEUPDATE(.T.) && Commits changes.
'Updated cLastName value: '
cLastName && Displays current cLastName value (Jones).

十豆三 2010-01-16
  • 打赏
  • 举报
回复
如果提交了,就不能还原。

一般这样:

设置缓冲,
修改
提交修改或放弃修改。

一旦提交修改了,就不能还原了。

你重点看一下这个
VFP 客户/服务器应用程序中的事务处理

*---------------------------------------------------

作者: Hector J. Correa

译者:RMH

--本文出自《天堂论坛》,若欲转载,敬请注明

我们都知道事务处理在数据库世界中是多么重要. 我们也知道 VFP 提供了杰出的事务处理支持. 但是, 当你的 VFP 应用程序使用另一种象 SQL Server 这样的 DBMS 来保存信息时会发生什么情况呢? 你是否还需要事务处理? 是的, 你需要. 你需要 VFP 的事务处理还是 SQL Server 的事务处理? 两者你都需要! Hector Correa 向你展示了为什么.

一般而言, 事务处理是访问数据库的一个程序单元. 在执行时, 事务处理可以接收并可能更新数据. 一个象 VFP 这样的数据库管理系统, 有执行事务处理的责任, 这样它才是原子的(OOP 术语:组合对象中的最小单元)和正确的. 要是原子的, 事务处理必须要么完成要么不执行.

使用事务处理允许你转换你从一个一致的状态转换你的数据库到另一个一致的状态. 如果一个数据库能够确保它的完整性约束则它是处于一致的状态. 在事务处理时, 数据库可能会处于不一致的状态. 但是, 如果完整性约束在事务处理结束时不能满足要求, VFP 必须终止事务处理并使数据库回到没有进行事务处理时的状态.

事务处理的典型示例包括银行传输 (从支票取走 $500, 减少 $500 存款) 和发票系统 (添加五个行项到一张发票, 从库存中移去五个项).

使用事务处理的优势是不可数的, 但基本的概念事务处理使你的生活更轻松, 因为你现在有一个个有力的, VFP 内置的机制来帮助你的数据库处于一种一致的状态.

现在, 让我们谈谈关于现实世界应用程序中的典型情节. 当你的 VFP 应用程序使用另一种象 SQL Server 这样的数据库管理系统来保存它的数据时会发生什么事? SQL Server 也支持事务处理. 你需要 SQL Server 的事务处理吗? 回答是需要. 你可以用 SQL Server 的事务处理来代替 VFP 的事务处理吗? 不, 两个你都需要. 让我们来看看为什么.

测试情节
在本文中, 我将用 VFP 的远程视图来访问并更新一个 SQL Server 数据库. 出于简单的原故, 我使用两个虚构的的 VFP 远程视图 (rv_MyView 和 rv_MyOtherView) 来访问两个 SQL Server 中的虚构的表 (MyTable 和 MyOtherTable). 图 1 显示了该情节是如何组织的.

我用 SQL Server 和 MSDE 测试了本文中的所示例. 但是, 如果你计划使用另一种 DBMS 作为你的后端, 你可能需要进行一点小小的调整.

在所附的下载文件中, 你可以找到更多的使用远程视图来访问和更新 SQL Server 7 的示例数据库 Northwind 数据库的例子.

没有事务处理的世界
在很大程度上, 事务处理是确保数据库的正确性的一种机制. 在完美的世界中, 你可能不需要事务处理. 以下代码不用事务处理来更新后端数据:

* 更新 VFP 游标中的数据.
replace balance with balance - 100 in rv_MyView
replace balance with balance + 100 in rv_MyOtherView

* 更新修改到 MyTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyView')
if lEverythingOK
* 更新修改到 MyOtherTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyOtherView')
endif
好了, 由于我们并不是生活在一个完美的世界上, 让我们看看如果更新 rv_MyView 成功而更新 rv_MyOtherView 失败会发生什么事.

第一个 TableUpdate() 将通知 VFP 执行一个 INSERT/UPDATE 命令到 SQL Server (例如, UPDATE myTable SET balance = 400 WHERE myTablePK = 'abc'). 一但该命令提交到后端, 后端处理它并告诉 VFP 命令成功地执行了. 第二个 TableUpdate() 失败—理由之一是后端不能处理所请求的命令--因为我正试图更新的记录被另一个用户删除了.

我将如何处理这种情况? 我已经更新了 MyTable 而且在 MyOtherTable 没有更新时不想保持这个修改. 当然, 我可以编写代码来保存 MyTable 的原始状态然后在发生错误时恢复它. 但是嗨, 这就是为什么正规的数据库管理系统中都有事务处理的能力. 让我们使用它!

事务处理命令
VFP 和 SQL Server 都提供了事务处理管理的相似的能力. 表 1 列出相等的命令.

表 1. VFP 和 SQL Server 中的事务处理命令.

VFP 命令/函数 SQL Server 中的等价物 (T-SQL)

Begin Transaction | Begin Transaction
| Set Implicit_Transactions On
End Transaction | Commit
Rollback | Rollback
TnxLevel() | @@TranCount


虽然两个 DBMS 提供了事务处理管理的相似的能力, 但也有一些你应该注意到的精细的区别.

第一个区别是 VFP 提供了 End Transaction 命令, 而 SQL Server 提供了 Commit 命令.

另一个差异是在嵌套事务处理时的 Rollback. 在 VFP 中, Rollback 仅撤消当前事务处理中的改变 (也就是说, 对于每一个事务处理你需要一个 Rollback 命令). 然而在 SQL Server 中, Rollback 撤消所有嵌套的事务处理直到远离事务处理 (因此, 无论你有多少嵌套的事务处理, 只需要一个 Rollback 命令).

另一个不同是允许的嵌套层数. VFP 允许嵌套至五级深度, 而 SQL Server 没有嵌套深度的限制.

使用 VFP 的事务处理
在处理远程视图时, 使用 VFP 的事务处理是直接了当的. 以下代码演示了如何做:

* 更新 VFP 游标中的数据.
replace balance with balance - 100 in rv_MyView
replace balance with balance + 100 in rv_MyOtherView
* 开始 VFP 事务处理.
begin transaction
* 更新修改到 MyTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyView' )
if lEverythingOK
* 更新修改到 MyOtherTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyOtherView')
endif
* 结束 VFP 事务处理.
if lEverythingOK
end transaction
else
rollback
endif
当发布一条 VFP begin transaction 命令时, 我请求 VFP 开始登录 VFP 游标中的每一个修改. 在最后, 我将发布一条 VFP end transaction 命令来接受那些修改, 或者用 VFP rollback 命令来废弃它们.

让我们看看与早先的示例相同的情形: 更新到 MyTable 成功, 但更新到 MyOtherTable 失败. 当这种情形发生时, lEverythingOK 将会是 .F., 因此, 我会 rollback 我的修改来撤消每一样东西到它的原始状态. 这就是所有真象, 但是让我们看看我所说的原始状态的意思.

我的两个视图在我发布 VFP begin transaction 前有一些未决的修改. 当我发布 begin transaction 时, 我请求 VFP 注意所发生的每一件事情. 然后, 当我更新 rv_MyView 后, VFP 发送那些修改到后端中的 MyTable 并标记 rv_MyView 为已更新的. 接着, 因为后端不能处理 MyOtherTable 的修改, 我的调用更新 rv_MyOtherView 失败. 在后端, 我 rolled back 事务处理, 因此, VFP 标记 rv_MyView 为未更新的 (也就是说, 它的原始状态).

现在, 让我们仔细看看在更新远程视图时 TableUpdate() 做了些什么. TableUpdate() 发送适当的 SQL 语句 (INSERT, UPDATE 或 DELETE) 到后端并且, 如果成功, 标记 VFP 游标为已更新的. 那是正确的, TableUpdate() 实际上发送了更新到后端.

你可能对修 rv_MyView 时发生了什么改感到疑惑. 我们知道它们确实发送到了后端并且后端接收了它们. 当我回滚 VFP 的事务处理时那些修改会被撤消吗? 不, 它们没有被撤消! VFP 标记 rv_MyView 为未更新的, 但它决不会告诉后端它需要忘记关于 MyTable 表中的修改.

换句话说, 使用 VFP 的事务处理, VFP 保存并撤消 VFP 游标中的原始状态, 而不是后端表的!

使用 SQL Server 的事务处理
正如你所看到的, 当你使用象 SQL Server 这样的其它的数据库管理系统时, 你需要一种机制来处理后端中的事务处理, 幸运的是, 除了 VFP 所提供的事务处理能力外, 大多数 DBMS 内置了该能力.

当你想在后端上开始一个事务处理时, 你所需要做的所有事就是发送一条命令到服务器来做该工作. 基本上有两种方法来完成该任务, 且两种方法都调用 SQL pass-through 函数.

第一种方法用 VFP SQLSetProp() 函数来启动服务器上的事务处理. 以下代码演示了如何这样做:

* 开始服务器上的事务处理.
nOldTransMode = dbgetprop( 'MyConnection', ;
'Connection', 'Transactions' )
SQLSetProp( nConnection, 'Transactions', DB_TRANSMANUAL )
* 更新修改到 MyTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyView' )
if lEverythingOK
* 更新修改到 MyOtherTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyOtherView' )
endif
* 结束服务器上的事务处理.
If lEverythingOK
SQLCommit( nConnection )
else
SQLRollback( nConnection )
Endif
* 恢复原始的事务处理模式.
SQLSetProp( nConnection, 'Transactions', nOldTransMode )
虽然它不是很直观, 但调用 SQLSetProp() 函数是一种实际启动 SQL Server 的事务处理方法. 设置 'Transactions' 属性为 DB_TRANSMANUAL 告诉 SQL Server 事务处理将手动地处理. 也就是说, 程序员钭发布一个明确的 rollback 或 commit 来指示结束事务处理. 当你发布该调用时, VFP 发送一个 SET IMPLICIT_TRANSACTIONS ON 命令到 SQL Server. 该命令选择一个轻快的版的 BEGIN TRANSACTION, 它延迟事务处理的开始直到真正被请求时 (例如, 当侦测到一个 UPDATE 命令时).

有另一种非直观的调用你必须用 VFP 内置的函数来处理服务器上的事务处理. 一但结果了你的事务处理, 必需确保设置事务处理模式回到它的原始状态 (最可能是 DB_MANUAL). 忘记这一步会在你的应用程序中产生大问题 (如, 锁定问题).

代替使用这些非直观调用和猜测 VFP 请求服务器做了什么, 我更喜欢自己发送事务处理命令到后端. 以下代码演示了该方法:

* 开始服务器上的事务处理.
SQLExec( nConnection, 'BEGIN TRANSACTION' )
* 更新修改到 MyTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyView' )
if lEverythingOK
* 更新修改到 MyOtherTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyOtherView' )
endif
* 结束服务器上的事务处理.
If lEverythingOK
SQLExec( nConnection, 'IF @@TRANCOUNT > 0 COMMIT' )
else
SQLExec( nConnection, 'IF @@TRANCOUNT > 0 ROLLBACK' )
Endif
以上代码一直运行到明确地发布 T-SQL 命令来开始和结束后端上的事务处理. 我发现该方法比用 VFP 内置的函数更易于阅读.

现在, 让我们看看如果 rv_View 更新成功而 rv_MyOtherView 失败时以上代码会发生什么情况. 我的第一个调用 SQLExec() 在后端上开始一个事务处理. 也就是说, 我现在请求后端保持跟踪所有的后端表气所发生的事. 然后, TableUpdate() 发送 rv_MyView 的修改到后端并标记游标为已更新的. 接着, 因为后端不能处理对 MyOtherTable 的修改, 我的第二个更新失败. 在结束时, 我请示后端回滚任何后端表中的已经执行了的修改.

两个最好的世界
以下示例代码演示了我的代码在同时使用 VFP 和 SQL Server 的事务处理时是如何做的:

* 开始一个 VFP 事务处理和一个服务器上的事务处理.
begin transaction
SQLExec( nConnection, 'BEGIN TRANSACTION' )
* 更新修改到 MyTable.
lEverythingOK = tableupdate( 2, .F., 'rv_MyView' )
if lEverythingOK
* 更新修改到 MyOtherTable.
lEverythingOK = tableupdate( 2,.F.,'rv_MyOtherView')
endif

* 结束服务器上的和 VFP 的事务处理.
If lEverythingOK
SQLExec( nConnection, 'IF @@TRANCOUNT > 0 COMMIT' )
end transaction
else
SQLExec( nConnection, 'IF @@TRANCOUNT > 0 ROLLBACK' )
rollback
Endif
正如你在最后的示例代码中看到的一样, 在 VFP 客户/服务器应用程序中处理事务处理是相当直接了当的. 作为一个黄金规则你应该意识到你是在处理两个 (不是一个) 数据库管理系统, 因此你的代码必须确保两个 DBMS 明白你对基本数据库的行为. 一但你这样做了, 确保你的数据库的正确性只是小菜一碟? 那怕你是生活在一个不太完美的世界中.
ACMAIN_CHM 2010-01-16
  • 打赏
  • 举报
回复
没有办法。这是SQL SERVER中的,只能通过备份来恢复。
ap7676 2010-01-16
  • 打赏
  • 举报
回复
学习了!
相关推荐
发帖
VFP

2577

社区成员

VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
帖子事件
创建了帖子
2010-01-15 08:43
社区公告
暂无公告