问题
I am quite not understanding the lock functionality with SELECT FOR UPDATE.
Here is what I've tried.
CREATE TABLE ACCOUNT_TAB (
ACC_ID int NOT NULL PRIMARY KEY,
BALANCE int NOT NULL
);
INSERT INTO ACCOUNT_TAB
VALUES(1, 100);
SELECT * FROM ACCOUNT_TAB FOR UPDATE;
SELECT * FROM ACCOUNT_TAB;
Both SELECT will retrieve the row, but shouldn't the first query lock the row in the ACCOUNT_TAB table?
I have read something about sessions: queries from the same session don't care about the lock. Can I somehow in a single script file demonstrate the lock function? For example, can I run two different sessions in one script so the second call will retrieve an error saying that the row is locked?
回答1:
Your original experiment failed to demonstrate the locking because in Oracle writes don't block reads. The FOR UPDATE clause allows us to avoid situations in which two sessions attempt to write to the same record; any number of sessions can read a record.
"Okay but still, is there some way to demonstrate the lock in a single script file?"
Yes. Here is a script with a local procedure which uses the autonomous_transaction
pragma to simulate a multi-user environment:
declare
procedure p1 (p_id in number) is
pragma autonomous_transaction;
cursor c23 is
select * from t23
where id = p_id
for update nowait;
r23 c23%rowtype;
begin
dbms_output.put_line('nested transaction');
open c23;
fetch c23 into r23;
update t23
set col2 = col2 * 2;
close c23;
commit;
exception
when others then
dbms_output.put_line(sqlerrm);
end;
begin
update t23
set col1 = 2
where id = 1;
p1 (1);
commit;
end;
/
The first UPDATE statement issues a lock, which causes the procedural call to fail because it can't get a lock (due to use of NOWAIT clause):
...
30 end;
31 /
nested transaction
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
PL/SQL procedure successfully completed.
SQL>
回答2:
RDBMS will obtain exclusive row-level locks on all rows identified by SELECT FOR UPDATE statement, so only you are the only one allowed to update them. It means that other RDBMS client won't be able to alter any of this records until you perform either a COMMIT or a ROLLBACK. So if you want to test how exactly it works, create two separate client connections and try first to lock record in one session, and then try to update same record in another one.
来源:https://stackoverflow.com/questions/44865703/oracle-select-for-update-demonstration