呵呵,楼主不亚,我就先来转一篇文章^_^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