Oracle에서 커밋 된 데이터베이스 격리 수준을 읽으십시오
-
13-09-2019 - |
문제
Oracle에 연결된 웹 앱에서 작업하고 있습니다. Oracle에는 "활성화 된"열이있는 테이블이 있습니다. 한 번만이 열만 설정할 수 있습니다. 이를 강화하기 위해 Java에서 직렬화 된 격리 수준을 사용하고 있지만 "거래 할 수 없음"오류가 발생하여 그 이유를 해결할 수 없습니다.
우리는 헌신적 인 독서 수준이 일을 할 것인지 궁금했습니다. 그래서 내 질문은 이것입니다.
다음 SQL과 관련된 거래가있는 경우 :
SELECT *
FROM MODEL;
UPDATE MODEL
SET ACTIVATED = 0;
UPDATE MODEL
SET ACTIVATED = 1
WHERE RISK_MODEL_ID = ?;
COMMIT;
이러한 트랜잭션 중 하나 이상이 동시에 실행할 수 있다는 점을 감안할 때, 하나 이상의 모델 행이 활성화 된 플래그를 1으로 설정할 수 있습니까?
모든 도움이 감사하겠습니다.
해결책
솔루션이 작동해야합니다. 첫 번째 업데이트는 전체 테이블을 잠그게합니다. 다른 트랜잭션이 완료되지 않으면 업데이트가 대기됩니다. 두 번째 업데이트는 테이블을 잠그고 있기 때문에 하나의 행만 값 1을 갖도록 보장합니다 (그러나 삽입 문을 방해하지는 않습니다).
또한 행에 RISK_MODEL_ID
존재합니다 (또는 트랜잭션이 끝날 때 '1'의 값이 0 인 경우).
동시 삽입 설명을 방지하려면 자물쇠 테이블 (독점 모드).
다른 팁
Oracle이 활성화 된 플래그가 1으로 설정된 1 행만 사용하는 제약 조건을 처리하기 위해 고유 한 기능 기반 색인을 사용하는 것을 고려할 수 있습니다.
CREATE UNIQUE INDEX MODEL_IX ON MODEL ( DECODE(ACTIVATED, 1, 1, NULL));
이것은 플래그를 1으로 설정하는 행이 하나 이상 중지되지만 플래그가 1으로 설정된 한 행이 항상 있다는 것을 의미하지는 않습니다.
원하는 것은 한 번에 하나의 트랜잭션 만 실행할 수 있도록하는 것이면 FOR UPDATE
통사론. 잠금이 필요한 단일 행이 있기 때문에 이것은 매우 효율적인 접근법입니다.
declare
cursor c is
select activated
from model
where activated = 1
for update of activated;
r c%rowtype;
begin
open c;
-- this statement will fail if another transaction is running
fetch c in r;
....
update model
set activated = 0
where current of c;
update model
set activated = 1
where risk_model_id = ?;
close c;
commit;
end;
/
그만큼 commit
자물쇠를 해방시킵니다.
기본 동작은 행이 해제 될 때까지 기다리는 것입니다. 그렇지 않으면 우리는 지정할 수 있습니다 NOWAIT
,이 경우 현재 활성 행을 업데이트하려는 다른 세션은 즉시 실패하거나 다음을 추가 할 수 있습니다. WAIT
폴링 시간이있는 옵션. NOWAIT
교수형의 위험을 절대적으로 피하도록 선택하는 옵션이며, 다른 사람이 알고 싶은 테이블을 업데이트하고 있음을 사용자에게 알릴 수있는 기회를 제공합니다.
이 접근법은 테이블의 모든 행을 업데이트하는 것보다 훨씬 확장 가능합니다. WW가 표시된대로 함수 기반 색인을 사용하여 한 행만이 활성화 될 수 있다는 규칙을 시행합니다. = 1.