您应该在事务结束时提交。我怀疑您能否找到一个合理的案例,即交易结束处于FOR UPDATE循环中间。
也许您听说过经常提交是一件好事。这是一个错误的神话,这是完全错误的。在 Oracle 中则相反:提交涉及额外的工作,因此您应该只在所有工作完成后才提交,而不是以前。
此外,从逻辑的角度来看,如果您可以从头开始而不是完成一半的工作,那么从错误中恢复会变得难以想象。
IMO,在程序中提交应该是非常罕见的。调用应用程序应该是进行必要检查并最终决定是否应提交数据的应用程序。
总之,您不能跨FOR UPDATE循环提交(它会产生一个ORA-01002: fetch out of sequence),这是一件好事。每当你发现自己在一个正常的循环中提交时,你应该问问自己提交是否真的有必要——很可能不是。
如果您确实需要提交并且只获取一次,那么在关闭游标之前或之后提交都没有关系。
在您的代码摘录之后更新:您的代码中有很多地方需要更正(我想它不是直接的生产代码,但仍然是):
永远不会引发异常:只有隐式SELECT INTO可以产生NO_DATA_FOUND.
SQL%ROWCOUNT如果前面的语句是 NULL,则为 NULL SELECT。
您可以使用c1%ROWCOUNT,但这只会返回获取的行数:0在初始open.
我主要使用FOR UPDATE NOWAIT这样两个会话永远不会互相阻塞。如果你只使用FOR UPDATE,你还不如使用一个UPDATE,而不是SELECT预先使用。
这是一个偏好问题,但返回码容易出错,通常首选异常。让错误传播。为什么有人会在id不存在的情况下调用此函数?这可能是调用应用程序/过程中的一个错误,所以你不应该抓住它。
所以你可以像这样重写你的程序:
CREATE OR REPLACE PROCEDURE Proc_UpdateCSClientCount(inMerid IN VARCHAR2,
outCliCount OUT NUMBER) AS
BEGIN
-- lock the row, an exception will be raised if this row is locked
SELECT CLIENT_COUNT + 1
INTO outCliCount
FROM OP_TMER_CONF_PARENT
WHERE MER_ID = inMerid
FOR UPDATE OF CLIENT_COUNT NOWAIT;
-- update the row
UPDATE OP_TMER_CONF_PARENT
SET CLIENT_COUNT = CLIENT_COUNT + 1
WHERE MER_ID = inMerid;
END;