首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >进度4GL独占锁未释放

进度4GL独占锁未释放
EN

Stack Overflow用户
提问于 2014-10-08 15:43:58
回答 3查看 4.1K关注 0票数 0

我正在使用proserve来启用多用户会话。这是我的代码,在一个鼠标双击触发器上浏览:

代码语言:javascript
复制
  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 locked“的消息。之后,会话B双击浏览记录1,它将在IF NOT AVAILABLE (EMPLOYEE)块中触发消息。

我的问题是,RELEASE EMPLOYEE代码不应该让会话B访问相同的记录吗?

我还尝试了FIND CURRENT EMPLOYEE NO-LOCK,并将这两个代码放在DO TRANSACTION块内部和外部,但什么也没有发生。

编辑:

我应用了这些更改,但在相同的场景中,会话B在ELSE块上收到消息MESSAGE "The record has been deleted in another session.".,我在这里做错了什么?

当我在MESSAGE STRING(EMPLOYEE.emp-num) + "locked.".之后添加对新窗口RUN newWindow.w.的调用时,使用相同的场景,同时没有关闭会话A上的新窗口,我得到了在会话B中的另一个会话中正在使用的记录的正确响应。

代码语言:javascript
复制
DO WITH FRAME MAIN-FRAME:
    IF EMP-BROWSE:NUM-SELECTED-ROWS > 0 THEN
    DO:        
        EMP-BROWSE:FETCH-SELECTED-ROW(1).   
        FIND CURRENT EMPLOYEE NO-LOCK NO-ERROR NO-WAIT.        
        DEFINE VARIABLE iOk AS LOGICAL NO-UNDO.
        DEFINE BUFFER myEMPLOYEE FOR EMPLOYEE.
        iOk = NO.
        DO FOR myEMPLOYEE TRANSACTION:
        FIND myEMPLOYEE WHERE myEMPLOYEE.emp-num = EMPLOYEE.emp-num EXCLUSIVE-LOCK NO-ERROR NO-WAIT.
        IF AVAILABLE (myEMPLOYEE) THEN
        DO:
            IF LOCKED (myEMPLOYEE) 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:
                C-Win:SENSITIVE = NO. 
                MESSAGE STRING(EMPLOYEE.emp-num) + " locked.". 
                C-Win:SENSITIVE = YES.   
            END.
        END.
        ELSE
        DO:
            MESSAGE "The record has been deleted in another session.".    
            RETURN NO-APPLY.
        END.
    END.
    END.
  END.  
EN

回答 3

Stack Overflow用户

发布于 2014-10-08 20:40:38

我想你有一些需要重新考虑的事情。

这一行:

代码语言:javascript
复制
FIND CURRENT EMPLOYEE NO-ERROR NO-WAIT.  

将导致共享锁定。有些人(包括我)倾向于避免这些。我将更改为:

代码语言:javascript
复制
FIND CURRENT EMPLOYEE EXCLUSIVE-LOCK NO-ERROR NO-WAIT.  

后面的一行:

代码语言:javascript
复制
IF AVAILABLE (EMPLOYEE) THEN

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

锁定函数

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

可用函数

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

FIND...NO-ERROR

禁止显示本来会发生的ABL错误或错误消息,并将它们转移到错误状态系统句柄。如果发生错误,则不会执行该语句的操作,而是继续执行下一条语句。如果该语句失败,则该语句的任何持续副作用都将被取消。如果语句包含包含其他可执行元素(如方法)的表达式,则由这些元素执行的工作可能完成,也可能不完成,具体取决于AVM解析表达式元素的顺序和错误的发生情况。

FIND...NO-WAIT

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

您可以将其更改为(并将ELSE语句更改为如下所示):

代码语言:javascript
复制
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,将来你也很可能想要这样做-如果代码已经很好地分离了关注点(例如图形用户界面、业务逻辑和数据访问),将来的现代化将会容易得多。

票数 0
EN

Stack Overflow用户

发布于 2014-10-08 21:09:44

RELEASE并不像你想的那样。使用RELEASE是一个危险信号。这几乎总是意味着编码人员没有很好地掌握记录和事务作用域问题。

从文档中:

RELEASE

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

注意到定义中没有提到锁吗?

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

正如Jens指出的那样,你的整个方法都需要重新考虑。

为了适当地控制记录和事务作用域,最佳实践是对此非常明确,并将更新限制在非常严格的代码块中。理想情况下,您可以将其封装在过程或函数中,如下所示:

代码语言:javascript
复制
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.

如果您不能将更新放在函数或过程中,那么您需要对用于更新记录的缓冲区进行“强作用域”:

代码语言:javascript
复制
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缓冲区的“自由引用”。如果编译器抱怨有问题,那么你需要修复它,因为你的作用域不是你想的那样。

票数 0
EN

Stack Overflow用户

发布于 2014-10-09 21:50:13

命令FETCH-SELECTED-ROW()已经使用在browse定义中定义的锁将浏览中的选定记录放入记录缓冲区,因此您不需要使用FIND语句来执行此操作。不管怎样,当我需要做你想做的事情时,我会使用像这样的代码:

代码语言:javascript
复制
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事件中的代码。然后,您可以将代码替换为如下所示:

代码语言:javascript
复制
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.

希望能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26251635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档