| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1647 人关注过本帖, 2 人收藏
标题:VFP 学习、开发漫谈 (18)
只看楼主 加入收藏
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:658
专家分:2180
注 册:2014-2-7
结帖率:96.88%
收藏(2)
已结贴  问题点数:20 回复次数:7 
VFP 学习、开发漫谈 (18)
今天与大伙聊一聊多用户编程方式下,如何减少数据共享冲突。

首先,用户越少,则冲突越少。从这一点来说,每台终端上可以仅允许运行一个应用程度窗口,防止应用程序重复运行。对于应用程序来说,每打开一个应用程序窗口,则意味着增加了一个“用户”。

实际应用中,可采取以下两种方法避免程序重复运行:

方法一:采用 API 函数 FindWindow()。但该方法要求应用程序的标题(即:_Screen.Caption)固定不变,有一定的局限性。
程序代码:
DECLARE Integer FindWindow IN win32api Integer,String
IF FindWindow(0,'物料管理系统') # 0
    MESSAGEBOX('程序已经运行!',64,'提示')
    QUIT
ENDIF

方法二:采用表独占法。该方法对应用程序的标题无任何限制。若应用程序的标题包含动态内容,如:“版本号”、“用户名”等,则应该采用此方法。
程序代码:
IF !DIRECTORY('C:\MIS')        && 建立临时文件夹
    MD C:\MIS
ENDIF
IF FILE('C:\MIS\FLAG.DBF')
    * 标记文件存在,则独占打开之。若不能打开,则说明程序已运行
    TRY
        USE C:\MIS\FLAG EXCLUSIVE
    CATCH
        MESSAGEBOX('系统已经启动!',48,'提示')
        QUIT
    ENDTRY
ELSE
    * 标记文件不存在,建立之
    CREATE TABLE C:\MIS\FLAG.DBF (UserName C(10))
ENDIF

上述示例中的 Flag.dbf 表不仅可以防止重复运行程序,还可用于保存程序的运行状态。如:本例保存的是登录用户名,这样可以在下次登录时,自动填入用户名。

减少共享冲突的另一个途径是,每个表单窗口仅允许打开一次。在 DO FORM 之前,先判断窗口是否已打开,若窗口已打开,则激活原窗口,否则再执行 DO FORM。以下代码做了精简,完整的代码请参考“漫谈(八)”中的 DoForm()函数。
程序代码:
cForm = 'employee'
W_Name = 'frm' + cForm
IF !WEXIST(W_Name)                && 窗口不存在时,运行表单
    DO FORM (cForm)
ELSE                              && 窗口存在时,激活窗口
    ACTIVATE WINDOW (W_Name) TOP  && 激活窗口
    IF WMINIMUM(W_Name)           && 最小化时还原
        ZOOM WINDOW (W_Name) NORM
    ENDIF
ENDIF

以上所述只是辅助手段,主要手段还得从表的结构设计入手。在设计表时,添加一个类似“制单人”或“用户”这样的身份识别字段,由系统自动维护,用于识别记录是由“谁”添加的。系统采取“谁添加,谁维护”的策略,这样可以避免多个用户同时对一条记录进行修改。也就是说,张三添加的记录只有张三有权修改,李四可以查询,但不能修改。当然,实际应用中还应该授权“管理员”对所有记录的修改权限,防止因人员变动而无法处理相关记录。

默认情况下,系统采取自动锁定。比如,在执行 Replace 命令时,系统会自动对记录进行加锁和解锁,若加锁不成功,系统可能处于无限等待状态(假死机)。我不喜欢这种处理方式,一般采用人工锁定方式,如下所述。

在表单的 Load 事件或数据环境的 BeforeOpenTables 事件中,添加 Set Reprocess to 0 Seconds,取消锁定失败后的自动重试。

自定义 3 个锁定函数:_FLock()、_RLock()、_HLock(),分别用于锁定表、锁定记录和锁定表头。这三个函数的代码大同小异,仅以 _FLock()为例,其代码如下:
程序代码:
* 功能:锁定表-----------------------------------------------------------------------------------------------------
* 参数:tcAlias:要锁定的表
* 返回:逻辑型,.t.:锁定成功,.f.:锁定失败
FUNCTION _FLock(tcAlias)
    LOCAL nSelect,nNum,nMax,lOK
    nSelect = SELECT()
    IF TYPE('tcAlias') = 'C' AND !EMPTY(tcAlias)
        SELECT (tcAlias)
    ENDIF
    nNum = 1     && 记录锁定的次数
    nMax = 10    && 最多锁定次数,约 5 秒
    lOK = .t.    && 是否锁定成功
    DO WHILE !FLOCK()
        WAIT WINDOW '正在对表“'+ALIAS()+'”进行锁定,请稍候……' TIMEOUT 0.5
        nNum = nNum + 1
        IF nNum > nMax
            IF MESSAGEBOX('无法锁定表“'+ALIAS()+'”,单击“重试”继续执行锁定,单击“取消”中止操作。',37,'提示')= 4
                nNum = 1
            ELSE
                MESSAGEBOX('数据库加锁失败,请稍后重试!',16,'提示')
                lOK = .f.
                EXIT
            ENDIF
        ENDIF
    ENDDO
    SELECT (nSelect)
    RETURN lOK
ENDFUNC

上述代码使用 FLOCK() 函数对表进行锁定,若锁定不成功,则再重试 9 次,每次间隔 0.5 秒。若重试 9 次后仍不能锁定,则提示用户选择重新开始锁定,还是放弃。比如,为所有财务部员工加薪 500元,可采用如下代码:
程序代码:
SELECT employee
IF _FLock()
    REPLACE salary WITH salary + 500 FOR department = '财务部'
    UNLOCK
ENDIF

在调用 _FLock() 函数对多个表进行数据处理时,有一定的技巧。比如:要对两个表进行操作,应该先对这两个表进行整体锁定,待锁定成功后再分别进行处理。这样,可以保证数据处理的完整性。不要先锁定一个表,待数据处理完毕后再锁定下一个表。
程序代码:
IF !_FLock('表1') OR !_FLock('表2')    && 锁定 2 个表
    UNLOCK ALL
    RETURN
ENDIF
REPLACE 字段 WITHIN 表1            && 处理表1中的记录
REPLACE 字段 WITHIN 表2            && 处理表2中的记录
UNLOCK ALL                             && 解除锁定

对表锁定后,应该立即执行数据处理,然后尽快解锁。不要在锁定表后再执行 MESSAGEBOX() 或 INPUTBOX()等执行时间不确定的操作,这些操作应该在锁定表之前执行。在对数据处理的过程中,若出现特殊情况需要中断程序运行时,应该先对表解除锁定,再执行 MESSAGEBOX()反馈信息。

所谓数据冲突,是指多个用户对同一记录进行修改时数据的相互覆盖。若出现了数据冲突,需要用到 CURVAL()、OLDVAL()、GETFLDSTATE()等函数,还需要将冲突提交给用户,由用户决定是选择强制更新,还是放弃操作,相当麻烦。

为了简化处理,我一般采取“谁最后提交,谁的数据有效”的原则,结合“谁添加,谁修改”策略,经实践检验是可行的,但这种方法不是绝对的。具体来说,就是在使用 Replace、Update、Delete等对无缓冲记录进行修改前,不判断数据冲突而直接进行修改。在对缓冲区数据进行更新时,采用 TABLEUPDATE(.t.,.t.) 格式,其中第二个参数.t.表示忽略冲突强制更新。

[ 本帖最后由 liuxingang28 于 2014-4-17 10:00 编辑 ]
搜索更多相关主题的帖子: 应用程序 实际应用 局限性 开发 如何 
2014-04-16 09:50
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
收藏
得分:7 
学习下
2014-04-16 11:34
flash7914
Rank: 2
等 级:论坛游民
帖 子:40
专家分:14
注 册:2013-4-7
收藏
得分:7 
又没拿到沙发啊
2014-04-16 14:19
hu9jj
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:红土地
等 级:贵宾
威 望:400
帖 子:11857
专家分:43421
注 册:2006-5-13
收藏
得分:7 
以下是引用flash7914在2014-4-16 14:19:41的发言:

又没拿到沙发啊
沙发、板凳不重要,重要的是获得知识或经验。

活到老,学到老!http://www.(该域名已经被ISP盗卖了)E-mail:hu-jj@
2014-04-16 17:48
鸥翔鱼游
Rank: 5Rank: 5
等 级:职业侠客
帖 子:182
专家分:323
注 册:2014-4-19
收藏
得分:0 
学到新知识了
2014-04-21 16:03
pzyun1985
Rank: 2
等 级:论坛游民
帖 子:106
专家分:18
注 册:2013-4-13
收藏
得分:0 
解决了俺滴单机版难题
2014-04-30 14:08
qshuju
Rank: 3Rank: 3
等 级:论坛游侠
威 望:3
帖 子:217
专家分:112
注 册:2011-6-9
收藏
得分:0 
方法一可写在主程序中,防止exe重复运行.

[ 本帖最后由 qshuju 于 2014-8-8 16:40 编辑 ]
2014-08-08 16:33
ILoveVFD
Rank: 3Rank: 3
等 级:论坛游侠
威 望:3
帖 子:218
专家分:147
注 册:2015-5-2
收藏
得分:0 
篇篇精彩!
2015-05-02 12:06
快速回复:VFP 学习、开发漫谈 (18)
数据加载中...
 
   



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

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