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)
我得到了这个查询作为我的问题以前的答案的一部分。现在如何锁定select查询中的行以确保没有其他线程写入我的更新。更新查询与选择和行锁
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)
我得到了这个查询作为我的问题以前的答案的一部分。现在如何锁定select查询中的行以确保没有其他线程写入我的更新。更新查询与选择和行锁
我不清楚你有什么问题,你似乎认为你有。
更新表中的行固有地在该行上放置行级锁。在通过提交或回滚来结束交易来释放锁之前,没有其他会话可以更新该行。完成交易后,其他会话可以自由覆盖您的更新。锁定SELECT
中的行是没有必要或有益的。
如果您正在尝试编写应用程序以避免丢失更新(即,您希望避免另一个会话更新与您提交事务后所做的相同的行,而无需先向其他用户显示更新的数据),则应用程序会需要实施某种附加锁定。最有效的方法是使用表中的某种LAST_UPDATE_TIMESTAMP
列实现乐观锁定。假设您在表中添加了此列(如果它尚未包含该列),则只要您向用户查询要呈现的数据,就会选择LAST_UPDATE_TIMESTAMP
,并且您将在UPDATE
中指定LAST_UPDATE_TIMESTAMP
。如果您的UPDATE
正好更新了1行,您知道自从您查询它以来没有人更改过数据。如果你的UPDATE
更新了0行,你会知道数据已经改变了,因为你查询了它并且你的应用程序需要采取适当的行动(即重新查询数据,重新呈现给用户,询问用户是否保留他们所做的任何未提交的更改等)。
但是,您的查询确实有其他问题。声明几乎肯定不会做你认为(或打算)做的事。此查询从MYTABLE
获得任意10行,其中PROCS_DT
为NULL,然后对这些任意10行进行排序。
SELECT
id
FROM mytable
WHERE
rownum<=10 and PROCS_DT is null
order by CRET_DT,PRTY desc
假设你真的想获得“十佳”的结果,你需要做的ORDER BY
在子查询应用ROWNUM
谓语前,即
SELECT
id
FROM (SELECT *
FROM mytable
WHERE procs_dt IS NULL
ORDER BY cret_dt, prty desc)
WHERE
rownum<=10
或者你可以使用一个解析函数,即
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
要锁定在Oracle中的行,你可以这样做:
SELECT *
FROM table1
WHERE some_condition
FOR UPDATE OF table1;
这是更好的,只是锁定你需要的行,而不是整个表。
参考这里: http://www.techonthenet.com/oracle/cursors/for_update.php
但在一般情况下,如果你用一个语句做UPDATE,你应该不需要担心锁定表或甚至行。这是您必须使用多个您需要锁定行的语句。
您需要使用此功能的场景是预订系统。考虑这个例子:
1. Execute SELECT to find out if room XYZ is available for a reservation on date X.
2. The room is available. Execute UPDATE query to book the room.
你在这里看到了潜在的问题吗?如果在步骤1和步骤2之间房间被另一笔交易记录下来,那么当我们到达步骤2时,我们正在进行一项不再有效的假设,即房间可用。但是,如果在步骤1中我们使用SELECT FOR UPDATE语句,我们确保没有其他事务可以锁定该行,所以当我们去更新行时,我们知道这样做是安全的。
谢谢。我认为我的情况也类似于您的酒店预订示例。我有2个node_index值为0和1的节点,它们可以同时执行相同的更新查询。在这种情况下,我希望不同的行集合被这些节点处理。如果我添加选择更新在我的内部查询它不工作。你的意思是我的更新陈述固有地处理了这种情况 – Shiv
@Shiv - 我不认为你需要在这里使用SELECT FOR UPDATE,因为你在单个操作中执行UPDATE。预留示例是查询某些行的位置,然后经过一段时间,然后更新这些相同的行。没有SELECT FOR UPDATE,那些行就可以改变。在你的情况下,你正在使用一个UPDATE语句,所以你的UPDATE语句将会看到你的语句开始执行时的行,除非你使用了一个不寻常的隔离级别。所以总而言之,我认为一个UPDATE语句应该可以工作。 – dcp
太好了。谢谢你.. – Shiv
“最有效的方法是使用ORA_ROWSCN伪列实现乐观锁定。“使用ORA_ROWSCN进行乐观锁定似乎存在问题。请参阅http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:2680538100346782134#2680546500346035086 –
+1指出OP的问题中的查询已损坏。 –
是的。感谢您在查询中解决问题。作为以前对我的堆栈溢出的答案的一部分q我实际上得到了你给我的确切查询。但是从我的结尾来看,这是错误的错误。 – Shiv