在 Oracle 中,我可以使用
选择排序表中的前 1 条消息select messageid from(
select
messageid,
RANK() over (order by messageid asc) as msg_rank
from messages
) where msg_rank=1;
正如我在上一个问题中发现的那样,我可以仅使用
选择一行select * from messages where rownum < 2 for update skip locked;
但是我无法将这两个概念合并在一起
select messageid from(
select
messageid,
RANK() over (order by messageid asc) as msg_rank
from messages
) where msg_rank=1 for update skip locked;
-- results in error
-- ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
如何通过 readpast 锁定选择前 N 个?
这行得通吗?
select messageid from messages
where messageid in (
select messageid from(
select
messageid,
RANK() over (order by messageid asc) as msg_rank
from messages
) where msg_rank=1
)
for update skip locked;
从事类似的任务,这是我的发现
SELECT BANNER_FULL FROM v$version
-- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
-- Version 19.8.0.0.0
CREATE OR REPLACE FUNCTION lockRows RETURN SYS_REFCURSOR IS
cur SYS_REFCURSOR;
BEGIN
OPEN cur FOR select /*+ FIRST_ROWS(10) */ TASK_ID from QUEUE where <...> FOR UPDATE SKIP LOCKED;
return cur;
END;
CallableStatement cs = connection.prepareCall("{ ? = call lockRows }")
cs.setFetchSize(topN);
cs.registerOutParameter(1, OracleTypes.CURSOR);
cs.execute();
ResultSet resultSet = (ResultSet) cs.getObject(1);
while(topN-- > 0 && resultSet.next()) {
String taskId = resultSet.getString(TASK_ID);
// update the row (where clause will not match it anymore)
}
删除
FIRST_ROWS
优化器提示和 setFetchSize
时没有注意到太大变化。
PreparedStatement ps = connection.prepareStatement(
"select /*+ FIRST_ROWS(10) */ TASK_ID from QUEUE where <...> FOR UPDATE SKIP LOCKED")
ps.setFetchSize(topN);
ps.execute();
ResultSet resultSet = ps.getResultSet();
while(topN-- > 0 && resultSet.next()) {
String taskId = resultSet.getString(TASK_ID);
// update the row (where clause will not match it anymore)
}
记录(记录)返回行数小于 topN 的所有出现情况。
这些事件只有在最后才会被注意到 - 一些工作人员获得的行数少于他们要求的行数。
如果准备好的语句确实会锁定表中的所有行,则会发生更多事件。
如果在PreparedStatement中使用ROWNUM -
where <...> and ROWNUM < topN
- 在很多事件中,工作人员获得的行数少于他们要求的行数。
在线阅读建议只有游标方法才能按预期执行,我编写了
PreparedStatement
实现只是为了验证它不起作用 - 1 个工作人员会锁定所有行,导致并发性较差。PreparedStatement
也可以正常工作。