进度4GL独占锁不释放

时间:2014-10-08 07:43:58

标签: session transactions locking progress-4gl

我使用proserve来启用多用户会话。 这是我的浏览器鼠标双击触发器中的代码:

  DO WITH FRAME MAIN-FRAME:
    IF EMP-BROWSE:NUM-SELECTED-ROWS > 0 THEN
    DO:
        EMP-BROWSE:FETCH-SELECTED-ROW(1).   
        FIND CURRENT EMPLOYEE NO-ERROR NO-WAIT.        
        IF AVAILABLE (EMPLOYEE) THEN
        DO:                 
            DO TRANSACTION ON ERROR UNDO, LEAVE:
                C-Win:SENSITIVE = NO.        
                FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK.
                MESSAGE STRING(EMPLOYEE.emp-num) + " locked.".                    
                C-Win:SENSITIVE = YES.   
            END.    
            RELEASE EMPLOYEE.                     
        END.
        ELSE IF NOT AVAILABLE (EMPLOYEE) THEN
        DO:
            MESSAGE "The employee details is currently in-use in another session. Please try again later." VIEW-AS ALERT-BOX TITLE "System Message".
            RETURN NO-APPLY.
        END.
        ELSE
        DO:
            MESSAGE "The record has been deleted in another session.".    
            RETURN NO-APPLY.
        END.      
    END.
  END. 

情景:
会话A双击浏览记录1.然后会发出类似" 2001锁定的消息。"在会话B双击浏览记录1之后,它将在IF NOT AVAILABLE (EMPLOYEE)块处触发消息。

我的问题是RELEASE EMPLOYEE代码启用会话B不应该访问同一条记录吗?

我也试过FIND CURRENT EMPLOYEE NO-LOCK并将{1}}块内部和外部的代码放在一起,但没有任何反应。

编辑:
我应用了这些更改,但在相同的情况下,会话B在DO TRANSACTION块上获取消息ELSE我在这里做错了什么?

当我在MESSAGE "The record has been deleted in another session.".之后添加对新窗口RUN newWindow.w.的调用时,在没有关闭会话AI的新窗口时使用相同的方案得到正确的记录响应在会话B的另一个会话中使用

MESSAGE STRING(EMPLOYEE.emp-num) + "locked.".

3 个答案:

答案 0 :(得分:0)

我认为你有一些事情需要重新考虑。

这一行:

FIND CURRENT EMPLOYEE NO-ERROR NO-WAIT.  

将导致SHARE-LOCK。有些人(包括我)倾向于避免这些。我会换成:

FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK NO-ERROR NO-WAIT.  

之后的行:

IF AVAILABLE (EMPLOYEE) THEN

只会处理记录的存在 - 而不是它的锁定状态。总而言之,考虑在线(F1)帮助:

  

已锁定功能

     

如果记录不适用于先前的FIND,则返回TRUE值。 。 。 NO-WAIT语句,因为另一个用户已锁定记录。

     

可用功能

     

如果您指定的记录缓冲区包含记录,则返回TRUE值;如果记录缓冲区为空,则返回FALSE值。

     

<强>查找... NO-错误

     

抑制否则会发生的ABL错误或错误消息,并将它们转移到ERROR-STATUS系统句柄。如果发生错误,则不执行语句的操作,并继续执行下一个语句。如果语句失败,则语句的任何持久副作用都将被撤消。如果语句包含一个包含其他可执行元素(如方法)的表达式,则这些元素执行的工作可能会也可能不会完成,具体取决于AVM解析表达式元素的顺序和错误的发生。

     

<强>查找... NO-WAIT

     

如果记录被另一个用户锁定(除非在同一个FIND语句中使用NO-ERROR选项),导致FIND立即返回并引发错误条件。例如:

您可以将其更改为(和ELSE语句类似):

FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK NO-ERROR NO-WAIT.  

IF LOCKED(EMPLOYEE) THEN DO:
    MESSAGE "Locked by another user".
END.
ELSE DO:
    IF AVAILABLE (EMPLOYEE) THEN DO:
        MESSAGE "Go ahead and change".
    END.
    ELSE DO:
        MESSAGE "Not available".
    END.
END.

请记住,您编写的代码是GUI,数据访问和业务逻辑之间的混合。这是一种不好的做法。您可以为较小的示例,测试和类似的事情做这件事,但实际上应该避免它。即使您现在没有使用AppServer,您很可能希望将来也能这样做 - 如果代码已经很好地分离了关注点(例如GUI,业务逻辑和数据访问),未来的现代化将会如此更容易。

答案 1 :(得分:0)

RELEASE不会按照您的想法执行。使用RELEASE是一个危险信号。它几乎总是意味着编码人员没有牢牢掌握记录和交易范围问题。

来自文档:

<强> RELEASE

验证记录是否符合必填字段和唯一索引定义。它清除缓冲区中的记录,并将其更改为数据库(如果已更改)。

请注意该定义如何解释锁定?

在事务中嵌入用户界面是一个重大错误 - 这样做基本上可以保证您将来会遇到锁争用问题和可伸缩性问题。

正如Jens指出你的整个方法需要重新思考。

为了正确控制记录和事务范围,最佳做法是对其进行非常明确,并将更新限制在非常严格的代码块中。理想情况下,您将其封装在过程或函数中,如下所示:

function updEmpName returns character ( input empNum as character, input newName as character ):

  define buffer employee for employee.

  do for employee transaction:
    find employee exclsuive lock where employee.employeeNum = empNum no-error.
    if locked employee then
      return "locked".
     else if available employee then
      do:
        assign
          employee.name = newName.
        .
        return "updated".
      end.
     else
      return "no such employee".
  end.
end.

如果您无法将更新放在函数或过程中,那么您需要“强范围”用于更新记录的缓冲区:

define variable ok as logical no-undo.
define buffer updEmployee for employee.

ok = no.

do for updEmployee transaction:
  find updEmployee exclusive-lock where updEmployee.employeeNum = empNum no-error.
  if available updEmployee then
    assign
      /* update whatever fields are needed */
      ok = yes
    .

end.

“DO FOR updEmployee”被称为“强范围”。这意味着该块之外的updEmployee缓冲区不能有“自由引用”。如果编译器抱怨存在问题,那么你需要修复它,因为你的范围不是你想象的那样。

答案 2 :(得分:0)

命令FETCH-SELECTED-ROW()已经使用在BROWSE定义中定义的LOCK将所选记录浏览到记录缓冲区中,然后您不需要使用FIND声明这样做。无论如何,当我需要做你想做的事情时,我会使用像这样的代码:

DO WITH FRAME {&FRAME-NAME}:

    DO iCount = 1 TO brEmployee:NUM-SELECTED-ROWS:

        brEmployee:FETCH-SELECTED-ROW(iCount).
        IF AVAIL Employee THEN DO:

            FIND CURRENT Employee EXCLUSIVE-LOCK.
            /* Do whatever I need */
            FIND CURRENT Employee NO-LOCK.

        END.
        ELSE DO:

            IF LOCKED(Employee) THEN DO:
                MESSAGE 'Record locked!'
                    VIEW-AS ALERT-BOX INFO BUTTONS OK.
            END.
            ELSE DO:
                MESSAGE 'Record deleted!'
                    VIEW-AS ALERT-BOX INFO BUTTONS OK.
            END.

        END.

    END.

END.

在此示例中,FETCH-SELECTED-ROW()离开返回记录。如果它不可用,您可以检查LOCKED条件。为避免浏览返回数据库中不存在的记录,您可以使用-rereadnolock会话参数。

但您在浏览的MOUSE-SELECT-DBLCLICK事件中使用了该代码。然后,您可以使用以下内容替换代码:

DO WITH FRAME {&FRAME-NAME}:

    brEmployee:SELECT-FOCUSED-ROW() NO-ERROR.
    IF AVAIL Employee THEN DO:

        FIND CURRENT Employee EXCLUSIVE-LOCK.
        /* Do whatever I need */
        FIND CURRENT Employee NO-LOCK.

    END.
    ELSE DO:

        IF LOCKED(Employee) THEN DO:
            MESSAGE 'Record locked!'
                VIEW-AS ALERT-BOX INFO BUTTONS OK.
        END.
        ELSE DO:
            MESSAGE 'Record deleted!'
                VIEW-AS ALERT-BOX INFO BUTTONS OK.
        END.

    END.

END.

希望它有所帮助。