我有一个包含2个函数的包含文件。其中一个功能非常好,所以我不会在其中包含它。我将包括导致问题的功能。
ss_update函数是导致我问题而不是按照我的假设释放锁的函数。我终于以这种方式工作添加了当前的screenstate no-lock。声明。我想知道是否有人可以向我解释这一点,以及是否有更好的方法来处理这种情况。
FUNCTION ss_update RETURNS INTEGER
( INPUT iUserName AS CHAR,
INPUT iScreenName AS CHAR,
INPUT iWidgetName AS CHAR,
INPUT iWidgetValue AS CHAR ):
DEFINE VARIABLE retStatus AS INTEGER NO-UNDO.
FIND ScreenState EXCLUSIVE-LOCK WHERE ScreenState.userName = iUserName AND
ScreenState.screenName = iScreenName AND
ScreenState.widgetName = iWidgetName NO-ERROR.
IF AVAIL ScreenState THEN
DO:
IF ScreenState.widgetValue <> iWidgetValue THEN
DO:
ASSIGN
ScreenState.widgetValue = iWidgetValue.
END.
retStatus = 1.
END.
IF NOT AVAIL ScreenState THEN
DO:
CREATE ScreenState.
ASSIGN
ScreenState.screenStateId = NEXT-VALUE(seq-ScreenStateId)
ScreenState.userName = iUserName
ScreenState.screenName = iScreenName
ScreenState.widgetName = iWidgetName
ScreenState.widgetValue = iWidgetValue.
retStatus = 2.
END.
/* This was added to release the lock. */
FIND CURRENT screenstate NO-LOCK.
RETURN retStatus.
END FUNCTION.
我的代码会连续几次调用更新函数。像这样......
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "t-ActiveOnly", t-ActiveOnly:SCREEN-VALUE).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "t-BadAdd", t-BadAdd:SCREEN-VALUE).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "LastCompany", company.companyId).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "rs-Filter", rs-Filter:SCREEN-VALUE).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "cb-Salesman", cb-Salesman:SCREEN-VALUE).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "cb-Search", cb-Search:SCREEN-VALUE).
ss_update(USERID(LDBNAME(1)), "FindComp2.w", "scr-Search", TRIM(scr-Search:SCREEN-VALUE)).
我遇到的问题是进度没有从上次调用的ss_update函数释放锁定。我不得不添加find current screenstate no-lock来降级锁。这看起来很丑陋而且没有正确编码,并且想知道为什么会发生这种情况以及处理这个问题的正确方法是什么。
答案 0 :(得分:3)
您的记录缓冲区是弱范围的,并且可能在程序中某处包含此函数的ScreenState引用。
这个功能很可能是借用&#34;来自主要街区的记录。
要修复它,有几种可能性。它很快又脏,但我喜欢做的事情之一是添加:
define buffer ScreenState for ScreenState.
位于函数定义的顶部。这看起来有点奇怪,但它的作用是强制所有对ScreenState的引用都是函数的本地引用。它阻止了意外的借款&#34;范围。
最终解决方案是强有力地记录记录并声明显式交易。该代码看起来像这样:
FUNCTION ss_update RETURNS INTEGER
( INPUT iUserName AS CHAR,
INPUT iScreenName AS CHAR,
INPUT iWidgetName AS CHAR,
INPUT iWidgetValue AS CHAR ):
define buffer ScreenState for ScreenState. /* prevent accidents from happening... */
define buffer updScreenState for ScreenState. /* used for updates */
DEFINE VARIABLE retStatus AS INTEGER NO-UNDO.
do for updScreenState transaction:
FIND updScreenState EXCLUSIVE-LOCK WHERE
updScreenState.userName = iUserName AND
updScreenState.screenName = iScreenName AND
updScreenState.widgetName = iWidgetName NO-ERROR.
IF available updScreenState THEN
DO:
IF updScreenState.widgetValue <> iWidgetValue THEN
DO:
ASSIGN
updScreenState.widgetValue = iWidgetValue.
END.
retStatus = 1.
END.
IF NOT available updScreenState THEN
DO:
CREATE updScreenState.
ASSIGN
updScreenState.screenStateId = NEXT-VALUE(seq-ScreenStateId)
updScreenState.userName = iUserName
updScreenState.screenName = iScreenName
updScreenState.widgetName = iWidgetName
updScreenState.widgetValue = iWidgetValue.
retStatus = 2.
END.
end.
RETURN retStatus.
END FUNCTION.
上面的代码定义了ScreenState和updScreenState - 严格来说,普通的旧ScreenState什么都不做,因为没有引用它。但如果有人稍后出现(或者如果我不知何故错过了),它将防止意外引用产生副作用。
使用updScreenState可以清楚地表明缓冲区是出于更新目的。
显式的TRANSACTION关键字清楚地定义了您希望事务开始的位置 - 如果编译器反对该事件,那么它会告诉您代码正在尝试执行您不期望的事情。
DO FOR块是什么&#34;强大的范围&#34; updScreenState缓冲区。如果存在对该块外部的updScreenState的杂散自由引用,编译器将对象。