업데이트 동작에 대한 Oracle 선택
우리가 해결하고자 하는 문제는 다음과 같습니다.
- 우리는 카드를 나타내는 줄로 가득 찬 테이블을 가지고 있습니다.예약 거래의 목적은 고객에게 카드를 할당하는 것입니다.
- 카드는 많은 클라이언트에 속할 수 없습니다.
- 얼마 후(구매하지 않은 경우) 카드를 다시 사용할 수 있는 재사용 가능한 풀로 반환해야 합니다.
- 여러 고객이 동시에 예약할 수 있습니다.
- 데이터를 저장하는 데 Oracle 데이터베이스를 사용하므로 솔루션은 Oracle 11 이상에서 작동해야 합니다.
우리의 해결책은 카드에 상태를 부여하고 예약 날짜를 저장하는 것입니다.카드를 예약할 때 "업데이트를 위해 선택" 문을 사용하여 예약합니다.쿼리는 사용 가능한 카드와 오래 전에 예약된 카드를 찾습니다.
하지만 우리의 쿼리가 예상대로 작동하지 않습니다.
문제를 설명하기 위해 간단한 상황을 준비했습니다.데이터로 가득 찬 card_numbers 테이블이 있습니다. 모든 행에 null이 아닌 번호가 있습니다.이제, 그것들 중 일부를 잠궈 보겠습니다.
-- first, in session 1
set autocommit off;
select id from card_numbers
where id is not null
and rownum <= 1
for update skip locked;
여기서는 거래를 하지 않습니다. 행이 잠겨 있어야 합니다.
-- later, in session 2
set autocommit off;
select id from card_numbers
where id is not null
and rownum <= 1
for update skip locked;
예상되는 동작은 두 세션에서 쿼리 조건을 만족하는 단일 다른 행을 얻는 것입니다.
하지만 그것은 그렇게 작동하지 않습니다.쿼리의 "잠금 해제" 부분을 사용하는지 여부에 따라 동작이 변경됩니다.
- 세션 1에서 트랜잭션 커밋 또는 롤백 대기 중인 "잠금 해제" 없음 - 두 번째 세션이 차단됨
- "filename locked" 포함 - 두 번째 쿼리는 즉시 빈 결과 집합을 반환합니다.
그래서, 이 긴 소개 후에 질문이 나옵니다.
Oracle에서 원하는 잠금 동작이 가능합니까?만약 그렇다면, 우리는 무엇을 잘못하고 있습니까?올바른 해결책은 무엇입니까?
업데이트 건너뛰기 잠금에 대해 발생한 동작은 이 블로그 노트에 설명되어 있습니다.FOR UPDATE 조항은 WHERE 조항 다음에 평가하는 것으로 알고 있습니다.SKIP LOCKED는 반환된 행 중에 잠긴 행이 없음을 보장하는 추가 필터와 같습니다.
당신의 진술은 논리적으로 다음과 같습니다: 첫 번째 행 찾기card_numbers
잠기지 않은 경우 반송합니다.분명히 이것은 당신이 원하는 것이 아닙니다.
다음은 사용자가 설명하는 동작을 재현하는 작은 테스트 사례입니다.
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
----------
두 번째 선택부터는 행이 반환되지 않습니다.커서를 사용하여 이 문제를 해결할 수 있습니다.
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
커서를 명시적으로 가져왔으므로 한 행만 반환되고 한 행만 잠깁니다.
다른 답변들은 이미 다양한 데이터베이스의 상황을 충분히 설명하고 있습니다.SELECT .. FOR UPDATE
변형 모델, Oracle이 사용을 권장하지 않는다는 점을 언급할 가치가 있다고 생각합니다.FOR UPDATE SKIP LOCKED
직접적으로 그리고 사용을 장려합니다.Oracle AQ
대신:
http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#i2066346
우리는 사용합니다.Oracle AQ
과 저는 다소 곡선에, 생산자/를 직접 꽤 될 수 것을 할 수 .
빈센트의 대답이 틀렸다는 것은 아니지만, 저는 다르게 설계했을 것입니다.
제 첫 번째 본능은 사용 가능한 첫 번째 레코드를 선택하고 "reserved_date"로 레코드를 업데이트하는 것입니다.XXX 시간이 경과하고 트랜잭션이 완료되지 않은 후 레코드의 reserved_date를 다시 null로 업데이트하여 레코드를 다시 확보합니다.
저는 가능한 한 단순하게 하려고 노력합니다.저는 이것이 더 간단합니다.
언급URL : https://stackoverflow.com/questions/5847228/oracle-select-for-update-behaviour
'prosource' 카테고리의 다른 글
Angular 5 - 브라우저 새로 고침 시 홈페이지로 페이지 리디렉션 (0) | 2023.06.12 |
---|---|
루프에 있는 동안 다른 변수 이름을 어떻게 생성합니까? (0) | 2023.06.12 |
"도..."가 있습니까?루비의 루프? (0) | 2023.06.12 |
Excel 축소 가능 들여쓰기 행 계층 만들기 (0) | 2023.06.12 |
package.json 내에서 환경 변수를 설정하는 방법은 무엇입니까? (0) | 2023.06.12 |