use*_*er1 2 oracle plsql stored-procedures oracle10g oracle11g
如果我在存储过程中使用FOR UPDATE子句应该何时"提交"?关闭打开的光标后或关闭打开的光标之前?以下是我正在使用的程序,我是以正确的方式做的吗?
CREATE OR REPLACE PROCEDURE Proc_UpdateCSClientCount(inMerid IN VARCHAR2,
outCliCount OUT NUMBER,
outretvalue OUT NUMBER)
AS
CURSOR c1 IS
SELECT CLIENT_COUNT
FROM OP_TMER_CONF_PARENT
WHERE MER_ID = inMerid
FOR UPDATE OF CLIENT_COUNT;
BEGIN
OPEN c1;
IF SQL%ROWCOUNT = 1 THEN
FETCH c1 INTO outCliCount;
outCliCount := outCliCount + 1;
UPDATE OP_TMER_CONF_PARENT
SET CLIENT_COUNT = outCliCount
WHERE CURRENT OF c1;
END IF;
outretvalue := 0;
CLOSE c1;
COMMIT;
EXCEPTION
WHEN no_data_found THEN
outretvalue := -1;
END;
Run Code Online (Sandbox Code Playgroud)
您应该在交易结束时提交.我怀疑你能找到一个合理的情况,即交易结束处于FOR UPDATE循环中间.
也许你听说经常提交是一件好事.这是一个虚假的神话,这是完全错误的.在Oracle中则相反:提交涉及额外的工作,因此您应该只在所有工作完成时提交,而不是之前.
此外,从逻辑的角度来看,如果你可以从头开始而不是完成一半的工作,那么从错误中恢复是不可想象的.
IMO,提交程序应该是非常罕见的.调用应用程序应该是进行必要检查的应用程序,最后决定是否应该提交数据.
总之,你不能在FOR UPDATE循环中提交(它会生成一个ORA-01002: fetch out of sequence),这是一件好事.每当你发现自己正在进行正常循环时,你应该问自己是否真的需要提交 - 很可能不是.
如果你真的需要提交并且只获取一次,那么在关闭游标之前或之后提交都没关系.
根据您的代码摘录进行更新:您的代码中有许多需要更正的内容(我认为它不是直接生产代码,但仍然是):
SELECT INTO生成NO_DATA_FOUND.SQL%ROWCOUNT如果前面的语句是a,则为NULL SELECT.c1%ROWCOUNT,但这只会返回获取的行数:0在初始之后open.FOR UPDATE NOWAIT这样两个会话永远不会互相阻塞.如果你只使用FOR UPDATE,你也可以使用一个,UPDATE而不是SELECT事先使用.id不存在的情况下调用此函数?这可能是调用app/procedure中的一个错误,所以你不应该抓住它.所以你可以像这样重写你的程序:
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;
Run Code Online (Sandbox Code Playgroud)