2014-08-27 2 views
0

У меня есть файл с 2 функциями. Одна из функций работает отлично, поэтому я не буду включать ее в это. Я включу функцию, вызывающую проблему.Блокировка транзакции, не высвобождающаяся на последней записи

Функция ss_update является той, которая вызывает у меня проблему и не освобождает блокировку, как я предполагал. Я, наконец, должен работать таким образом, добавляя текущую функцию show no screen. заявление. Мне интересно, может ли кто-нибудь объяснить это мне, и если есть лучший способ справиться с этой ситуацией.

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 функции. Мне нужно было добавить текущее состояние экрана без блокировки, чтобы понизить блокировку. Это просто кажется уродливым и неправильно закодированным и задается вопросом, почему это произошло и каков правильный способ справиться с этой проблемой.

ответ

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 дает понять и очевидно, что буфер предназначен для целей обновления.

Явное ключевое слово TRANSACTION четко определяет, где вы ожидаете, что транзакция начнется - если компилятор возражает против этого, то он сообщает вам, что ваш код пытается сделать то, чего вы не ожидали.

Блок DO FOR - это то, что «сильные области применения» буфера updScreenState. Компилятор будет возражать, если есть свободные ссылки на updScreenState, лежащие вне этого блока.

+0

Отличный Том. Спасибо за объяснение, а также за решение. Очень ученик, и это работало как шарм. – dayv2005

Смежные вопросы