更新缓冲区并将锁定模式重置为原始

时间:2017-03-30 09:05:30

标签: database progress-4gl openedge progress-db

假设我们有一个程序,它接受buffer - 参数:

myprocedure.p:

DEF PARAM BUFFER bufferParameter FOR DatabaseTable.

/* Get the same buffer in EXCLUSIVE-LOCK for updating */
FIND CURRENT bufferParameter EXCLUSIVE-LOCK.

/* Update the value */
ASSIGN bufferParameter.MyField = "new value".

/* Reset the locking mode back to the original one? */
FIND CURRENT bufferParameter NO-LOCK.

这种方法的问题在于它可能会更改传递的locking-mode的原始buffer parameter。缓冲区可能位于EXCLUSIVE-LOCK中的NO-LOCK或f.ex中。通过更改locking-mode,此过程可以使用相同的buffer调用某些其他程序中的更新错误。

另一个解决方案是为同一个表创建一个新的temporary buffer,然后通过该缓冲区更新数据库(不触及传递的参数缓冲区)。这种方法的结果是原来通过的buffer parameter将变得“过时”。它需要一个新的数据库查询来更新它的'MyField'值以匹配数据库中的值。

如何在更新缓冲区的locking-mode之后将缓冲区的fields重置回原来的那个?

5 个答案:

答案 0 :(得分:2)

这个帖子可能是有用的背景 - 它讨论了如何找出当前的锁定状态。

http://stackoverflow.com/questions/26136842/progress-4gl-display-buffer-lock-type?rq=1

最终我认为这是你真正需要的:

    /* lightly tested psuedo code...
     */

    procedure updateMyField:

      define input parameter myRowid  as rowid.

      define buffer updMyTable for myTable.  /* this limits the scope of the buffer to this procedure */

      do for updMyTable transaction:  /* FOR "strong scopes" the buffer to this block */
        find updMyTable exclusive-lock where rowid( updMyTable ) = myRowid no-error.  /* the EXCLUSIVE-LOCK is scoped the FOR block -- when we leave the block it is released */
        if available updMyTable then
          assign
            updMyTable.myField = "new value"
          .
         else
          do:
            message "could not get an exclusive-lock on myTable".
            /* or whatever error handling you need... */
          end.
      end.  /* the transaction is committed and the lock is released -- no need to change its status */

      return.

    end.

    /* main block
     */

    find first myTable no-lock.
    display myTable.myField.
    pause.

    run updateMyField ( rowid( myTable )).

    find first myTable no-lock.
    display myTable.myField.
    pause.

答案 1 :(得分:1)

奇怪的是,锁类型不是缓冲区句柄的属性。这似乎是一个显而易见的必要条件。

你可以找到recid的_lock记录,但你也需要找到表ID,这意味着在句柄:table中查找_file。

因此,假设您只连接了一个数据库,那么您将拥有类似的内容:

FIND _file NO-LOCK WHERE _file-name = bufHandle:TABLE.
FIND _lock NO-LOCK WHERE _lock-name = USERID()
    AND _lock-table = _file-number
    AND _lock-recid = bufHandle:RECID.

如果记录存在,则表示您已锁定。 _lock_flags会告诉你你有什么样的锁。我认为S是分享而且E是独家的,并且如果有Q则认为你正在等待锁定,如果你已经锁定记录,我不会期望。

如果在您的功能开始时它已经完全锁定,您可以将记录重新锁定在适当的状态。

答案 2 :(得分:1)

当您在交易中时,实际上无法解锁记录。如果您尝试,则在事务结束并将更改提交到数据库之前,独占锁将成为一个限制锁。这是为了防止数据完整性问题。如果你正在查看_Lock-Flags字段,那么limbo lock将是" L"。您还可以使用Promon来检查锁表状态。

根据您锁定和更新记录的方式,事务可以限定为不同的过程。您可以通过在代码中粘贴此行来查看您是否参与了交易:

MESSAGE TRANSACTION VIEW-AS ALERT-BOX.

这是关于记录锁定和事务范围的OpenEdge文档: https://documentation.progress.com/output/ua/OpenEdge_latest/index.html#page/gsabl/handling-data-and-locking-records.html#

答案 3 :(得分:0)

我认为你的第二个解决方案就是使用它。定义一个本地缓冲区(不需要将其称为临时缓冲区,这在OpenEdge IMO中不是明确定义的术语),使用rowid将参数记录加载到此缓冲区中(如果参数缓冲区已被锁定,则基本上是自由操作)并更改您的本地缓冲区。 不要担心任何过时的事情。引用http://knowledgebase.progress.com/articles/Article/P4548(请阅读完整文章)

  

在客户端记录池中,任何时候都只允许存在一个记录副本。这意味着在以下情况中显示两个缓冲区指向客户1的同一物理副本。   这意味着执行以下代码后

DEFINE BUFFER cust FOR customer.
DEFINE BUFFER cust1 FOR customer.
FIND FIRST cust no-lock.
FIND cust1 where rowid(cust1) = rowid(cust) exclusive-lock.
cust1.name = 'xyz':U.

cust.name也将具有值'xyz'。 我只是尝试了代码来确定。事实上,我也确认锁定不在缓冲区上,而是在记录上。即使查找到cust使用no-lock,我也可以分配cust.name。 如果您的程序/程序之外还没有事务,则在退出程序时将释放锁定。 绝对不要尝试使用_lock,除非有必要向锁定他想要更改的记录的用户(或类似目的)显示。

答案 4 :(得分:0)

所以当我认为当具有相同记录的另一个缓冲区更新了相同记录时原始缓冲区没有更新时,我发现我错了。

因此更新传递的缓冲区的一个好方法是通过<html> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script> <body> <div ng-app="myApp" ng-controller="testCtrl" > {{company}} <table><tr><th>id</th><th>Name</th><th>Rating</th> </tr> <tr ng-repeat="com in company"> <td>{{com.id}}</td> <td>{{com.name}}</td> <td> <input type="text" ng-model="com.rating" ng-change="addRatingbyId(com)"> </td> </tr></table> <input type="submit" ng-click="sendRating()"> {{Newrat}} </div> </body> </html>获取相同的记录并分别在另一个缓冲区中更新它:

Post.joins("LEFT OUTER JOIN users ON posts.user_id = user.id")
    .where("user.id IS NULL")

ROWID似乎处理所有数据更改并相应地更新缓冲区。但是,我认为如果有两个单独的程序运行,f.ex DEF BUFFER myFirstBuffer FOR MyTable. DEF BUFFER mySecondBuffer FOR MyTable. FIND FIRST myFirstBuffer WHERE myFirstBuffer.MyField = "myvalue" NO-LOCK. /* At this moment myFirstBuffer.MyField is "myvalue" */ FIND FIRST mySecondBuffer WHERE ROWID(mySecondBuffer) = ROWID(myFirstBuffer) EXCLUSIVE-LOCK. ASSIGN mySecondBuffer.MyField = "mynewvalue". /* Now both 'myFirstBuffer.MyField' and 'mySecondBuffer.MyField' match ("mynewvalue")! */ Progress并且它们都在不同的时间更新相同的记录,这不起作用(尽管这是另一个故事。 ..)。 早些时候,当触发器影响字段未在缓冲区上更新时,我们遇到myprogram1.p个问题。

但简而言之,我认为最好用myprogram2.p分别查询记录并以这种方式更新。我相信开发人员不应该使用TRIGGER,因为这会更改记录的ROWID,并且可能会在以后使用FIND CURRENT myBuffer NO-LOCK.破坏逻辑。