2014-08-27 67 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