使用select和row lock更新Query

jun*_*sal 2 sql oracle locking oracle11g

update mytable set node_index=0 where id in (
        SELECT 
            id
         FROM mytable
         WHERE 
            rownum<=10 and PROCS_DT is null  
         order by CRET_DT,PRTY desc) 
Run Code Online (Sandbox Code Playgroud)

我把这个查询作为我之前问题答案的一部分.现在如何锁定select查询中的行以确保没有其他线程写入我的更新.

Jus*_*ave 5

我不清楚你有没有看到你认为有的问题.

更新表中的行本身会在该行上放置行级锁.在通过提交或回滚结束事务来释放锁之前,没有其他会话可以更新该行.完成交易后,其他会话可以自由覆盖您的更新.锁定行中没有必要或好处SELECT.

如果您正在尝试编写应用程序以避免丢失更新(即,您希望避免另一个会话更新您在提交事务后执行的相同行而不向其他用户显示您的更新数据),您的应用程序将需要实现一些额外的锁定.最有效的方法是使用LAST_UPDATE_TIMESTAMP表中的某种列来实现乐观锁定.假设你添加了此列表,如果它不已经有一个,你会选择LAST_UPDATE_TIMESTAMP当你查询的数据呈现给用户,你会指定LAST_UPDATE_TIMESTAMP你的UPDATE.如果您UPDATE更新了正确的1行,则您知道自查询以来没有人更改过数据.如果UPDATE更新了0行,您就会知道数据已经更改,因为您查询了它并且您的应用程序需要采取适当的操作(即重新查询数据,将其重新呈现给用户,询问用户是否保留他们所做的任何未提交的更改等).

但是,您的查询确实有另一个问题.该SELECT语句几乎肯定不会做你认为是什么(或准备)为它做.该查询会从任意10行MYTABLE,其中PROCS_DT为NULL,然后下令那些任意10行.

         SELECT 
            id
         FROM mytable
         WHERE 
            rownum<=10 and PROCS_DT is null  
         order by CRET_DT,PRTY desc
Run Code Online (Sandbox Code Playgroud)

假设您实际上想要获得"前10名"结果,则需要ORDER BY在应用ROWNUM谓词之前在子查询中执行此操作,即

         SELECT 
            id
         FROM (SELECT *
                 FROM mytable
                WHERE procs_dt IS NULL
                ORDER BY cret_dt, prty desc)
         WHERE 
            rownum<=10 
Run Code Online (Sandbox Code Playgroud)

或者你可以使用分析函数,即

         SELECT 
            id
         FROM (SELECT m.*,
                      rank() over (ORDER BY cret_dt, prty desc) rnk
                 FROM mytable m
                WHERE procs_dt IS NULL)
         WHERE 
            rnk<=10 
Run Code Online (Sandbox Code Playgroud)

  • "最有效的方法是使用ORA_ROWSCN伪列实现乐观锁定." 使用ORA_ROWSCN进行乐观锁定似乎存在问题.见http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:2680538100346782134#2680546500346035086 (2认同)