1

이 질문에 대한 대답은 DBMS에에 의존하는 경우, 내가 오라클 11g 이상 및 SQL Server에 대한 대답을 듣고 싶네 2012직렬화 INSERT들

우리가 참조하는 외래 키가있는 테이블을 자체 :

CREATE TABLE Versions (
    Id INT IDENTITY(1,1) NOT NULL, 
    [Date] DATETIME NOT NULL, 
    BasedOnVersion INT NULL -- foreign key that references Versions 
) 

Versions 테이블에 새 레코드를 삽입하는 저장 프로 시저가 있습니다.

How it should run       

Transaction 1 reads current version 17 
Transaction 1 writes new version 18 based on 17 
Transaction 2 reads current version 18 
Transaction 2 writes new version 19 based on 18 

How it should NOT run 

Transaction 1 reads current version 17 
Transaction 2 reads current version 17 
Transaction 1 writes new version 18 based on 17 
Transaction 2 writes new version 19 based on 17 

:이 동시에 실행하는 경우, 우리는 두 개의 버전이 동일한 다른 버전을 참조 없기 때문에 (우리가 의도적으로 포크를 만드는 제외) 버전 계층 구조에있는 포크가 안된다는 것을 확인해야 두 번째 경우에는 동일한 버전을 기반으로하는 두 가지 버전이 있습니다.

두 트랜잭션을 직렬화하는 방법이 필요합니다. 먼저 ISOLATION LEVEL SERIALIZABLE을 사용하려고 생각했지만 격리 수준은 INSERTs에 아무런 영향을 미치지 않으므로 해결 방법이 아닙니다.

또 다른 방법은 트랜잭션 시작시 Versions 테이블의 잠금을 획득하는 것입니다. 오라클의 LOCK TABLE IN EXCLUSIVE MODE은 트랜잭션 2가 테이블을 읽지 못하도록하기 때문에 SQL 서버에서는 작동하지만 오라클에서는 작동하지 않습니다.

그래서 이런 종류의 문제에 가장 적합한 해결책은 무엇입니까?

답변

1

이것은 "손실 된 업데이트 문제"로 알려져 있으며 여러 가지 해결책이 있습니다. 그들 모두가 비관적 인 자물쇠를 요구하는 것은 아닙니다.

한 가지 방법은 WHERE 절에있는 조건자를 사용하는 "쓰기"메소드를 수정하여 현재 버전이 세션이 읽는 것과 같지 않은 경우 버전 업데이트를 중지합니다.

  1. 즉, 트랜잭션 (1) 현재 버전 읽기 17
  2. 트랜잭션이 현재 버전 17
  3. 거래 (1)가 새 버전 (18)을 작성하는이 개 시도 17
  4. 거래를 기반으로 새 버전 (18) 읽기와 쓰기, 그러나 UPDATE v=18 WHERE v=17 결과는 "0 records updated"이며 세션은 이것을 오류로 처리합니다. "다른 사용자가이 버전을 수정했습니다. 다시 쿼리하여 다시 시도하십시오."

나는 2005 년이 뒷면에 쓴 방법의 수가 나열 :

http://jeffkemponoracle.com/2005/10/21/avoiding-lost-updates-protecting-data-in-a-multi-user-environment/

1

버전에 시퀀스를 사용할 수 있습니다. 시퀀스는 동시 작업에 안전합니다.

그래서;

Transaction 1 reads nextvalue version 18 (So current is 18 - 1 = 17) 
Transaction 2 reads nextvalue version 19 (So current is 19 - 1 = 18) 
Transaction 1 writes new version 18 based on 17 
Transaction 2 writes new version 19 base on 18 
1

그가 직렬화 가능 트랜잭션에 포함되어있는 경우 개별적으로 삽입 또는의 한 부분으로, 다음 삽입이 될 것입니다, 그래서

select MAX(ID) from Versions 

의 라인을 따라 최신 버전을 확인 보인다 serializable

set transaction isolation level serializable 

begin tran 
    insert Versions (basedonversion) 
    select MAX(ID) from Versions 
commit tran