2014-08-27 33 views
0

我有一个包含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函数的锁。我不得不添加查找当前screenstate无锁来降级锁。这看起来很丑陋,没有正确编码,不知道为什么发生这种情况,以及处理这个问题的正确方法是什么。

回答

3

您的记录缓冲区弱作用域和可能存在于包括该功能的程序某处ScreenState参考。

的功能是可能的“借”从主块的记录。

要修复它,有几种可能性。这是快速和肮脏的,但我喜欢做的事情之一是添加:

define buffer ScreenState for ScreenState. 

在函数定义的顶部。这可能看起来有些奇怪,但它所做的是强制所有对ScreenState的引用都是本地函数。它阻止了意外的“借贷”范围。

最终的解决方案是强大范围的记录和声明明确的交易。该代码是这样的:

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清楚和明显的缓冲是更新的目的。

的明确的事务关键字明确规定,你希望交易开始 - 如果编译对象到那么它是告诉你,你的代码是试图做一些事情,你没有想到的。

块的DO是什么“强范围”的updScreenState缓冲区。如果存在对位于该块外部的updScreenState的空闲引用,编译器将会进行响应。

+0

优秀的汤姆。感谢您的解释和解决方案。大大地学徒,它像一个魅力。 – dayv2005 2014-08-27 16:17:35