Perilaku yang Anda temui untuk FOR UPDATE SKIP LOCKED telah dijelaskan dalam catatan blog ini. Pemahaman saya adalah bahwa klausa FOR UPDATE dievaluasi SETELAH klausa WHERE. SKIP LOCKED seperti filter tambahan yang menjamin bahwa di antara baris yang akan dikembalikan, tidak ada yang dikunci.
Pernyataan Anda secara logis setara dengan:temukan baris pertama dari card_numbers
dan kembalikan jika tidak terkunci. Jelas ini bukan yang Anda inginkan.
Berikut ini adalah kasus uji kecil yang mereproduksi perilaku yang Anda gambarkan:
SQL> CREATE TABLE t (ID PRIMARY KEY)
2 AS SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 1000;
Table created
SESSION1> select id from t where rownum <= 1 for update skip locked;
ID
----------
1
SESSION2> select id from t where rownum <= 1 for update skip locked;
ID
----------
Tidak ada baris yang dikembalikan dari pilihan kedua. Anda dapat menggunakan kursor untuk mengatasi masalah ini:
SQL> CREATE FUNCTION get_and_lock RETURN NUMBER IS
2 CURSOR c IS SELECT ID FROM t FOR UPDATE SKIP LOCKED;
3 l_id NUMBER;
4 BEGIN
5 OPEN c;
6 FETCH c INTO l_id;
7 CLOSE c;
8 RETURN l_id;
9 END;
10 /
Function created
SESSION1> variable x number;
SESSION1> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
1
SESSION2> variable x number;
SESSION2> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
2
Karena saya telah mengambil kursor secara eksplisit, hanya satu baris yang akan dikembalikan (dan hanya satu baris yang akan dikunci).