| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2156 人关注过本帖
标题:VFP与SQL SERVER 事务问题
只看楼主 加入收藏
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
 问题点数:0 回复次数:7 
VFP与SQL SERVER 事务问题
本人是个新手,想搞点C/S的小程序.但现在对事务没有什么了解.请教如下:

比如有A,B两父子关系表,如入库单号表与入库单明细表
通常对数据库更新前,执行人工事务
A表增加了一行入库单号,B表也应跟着增加与A相对应的一行或数行明细数据.
但如果A增加之后,客户端掉线或死机了,服务器将无法收到客户端的回滚指令.
这时,服务器的数据就不对了.
如果收不到客户端的回滚指令,服务器是不是一直在挂着呢?
有没有办法,让服务器进入人工事务后,如果过了一定的秒数后还收不到客户端的事务结束或回滚指令的话,能自动回滚事务呢?

另外,如何在更新前对数据库是否在线进行检测,若因网络问题让据库服务器与客户端连接断开了,如何检测并让它自动重新连上?

请高手指点!

[[it] 本帖最后由 h678999 于 2008-9-13 10:05 编辑 [/it]]
搜索更多相关主题的帖子: SQL VFP SERVER 事务 
2008-09-12 17:37
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
得分:0 
怎么没有人帮助我?急用呀,再次求教!
2008-09-16 16:38
ibmlang_002
Rank: 5Rank: 5
来 自:浙江-嘉兴
等 级:贵宾
威 望:18
帖 子:437
专家分:176
注 册:2008-8-30
收藏
得分:0 
我们都知道事务处理在数据库世界中是多么重要. 我们也知道 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 明白你对基本数据库的行为. 一但你这样做了, 确保你的数据库的正确性只是小菜一碟? 那怕你是生活在一个不太完美的世界中.

[[it] 本帖最后由 ibmlang_002 于 2008-9-17 17:11 编辑 [/it]]

VFP
2008-09-17 17:05
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
得分:0 
看过三楼仁兄的回复,我对事务有初步了解了.非常感谢!

以上的事务处理,在C与S两端都工作正常下,能达到要求.

在客户端掉线或死机了,服务器将无法收到客户端的提交或回滚指令.服务器会不会一直在挂着等呢?出现这种情况怎办?

另外,如何在更新前对数据库是否在线进行检测,若因网络问题让据库服务器与客户端连接断开了,如何检测并让它自动重新连上?

继续求教!
2008-09-22 16:58
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
得分:0 
没人帮我,只好自己顶一下先了
2008-09-23 11:37
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
得分:0 
这种情况没有人试过吗?
2008-09-23 14:53
h678999
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2008-9-12
收藏
得分:0 
10多天了,还是没有找到答案,VFP真的很少人用了吗?
2008-09-25 16:06
pgshui
Rank: 1
等 级:新手上路
帖 子:10
专家分:0
注 册:2006-4-27
收藏
得分:0 
你可以用SQL存储过程处理呀,那就不要担心客户端掉线或死机/网络问题了

VFP仅作前台输入参数、返回结果

[[it] 本帖最后由 pgshui 于 2008-9-28 17:20 编辑 [/it]]
2008-09-28 17:18
快速回复:VFP与SQL SERVER 事务问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.048567 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved