설정 IDENTITY_INSERT ON
자체에 동시성을 제거하지 않습니다 -이 테이블 만 간단한 스키마 안정성 (SCH-S) 잠금을 배타적 잠금을하지 않습니다.
이론적으로 기본 동작에서 발생할 수있는 일은 세션 1에서 수행 할 수 있다는 것입니다.
BEGIN TRANSACTION;
-- 1
SET IDENTITY_INSERT dbo.tablename ON;
-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101
-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102
-- 4
SET IDENTITY_INSERT dbo.tablename OFF;
COMMIT TRANSACTION;
다른 세션에서는 포인트 1, 2, 3 또는 4에서 테이블에 행을 삽입 할 수 있습니다. 2와 3 사이에서 발생하는 삽입에 대해 발생하는 것을 제외하고는 좋은 일처럼 보일 수 있습니다 . 자동 생성 된 값이 트리거 된 것입니다. 다른 세션에서는 명령문 2의 결과를 기반으로하므로 101을 생성 한 다음 기본 키 위반으로 명령문 3이 실패합니다. 이것은 약간 WAITFOR
의 설정으로 자신을 설정하고 테스트하는 것이 매우 간단합니다 .
-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;
SET IDENTITY_INSERT dbo.what ON;
INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);
SET IDENTITY_INSERT dbo.what OFF;
COMMIT TRANSACTION;
해당 배치가 시작되면 다른 창에서이 배치를 시작하십시오.
-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20
세션 2는 1-20 사이의 값만 삽입해야합니다. 수동 삽입 세션 1에서 기본 ID가 업데이트 되었기 때문에 어느 시점에서 세션 2는 세션 1이 중단 된 위치를 선택하고 32, 33 또는 34 등을 삽입합니다. 그러나이 작업은 허용됩니다. PK 위반으로 다음 삽입에서 세션 1이 실패합니다 (이기는 시간 문제 일 수 있음).
이 문제를 해결하는 한 가지 방법 TABLOCK
은 첫 번째 삽입에서 를 호출하는 것 입니다.
INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);
이렇게하면 아카이브 된 행을 다시 이동할 때까지이 테이블에 삽입하거나 실제로 수행하려는 다른 사용자를 차단합니다. 이 조절판 동시성은, 물론,하지만 당신이 방법은 원하는 작업에 차단. 그리고 이것이 여러분이 다른 사람들을 항상 차단하는 빈번한 속도로 일어나지 않는 것이기를 바랍니다.
몇 가지 다른 해결 방법 :
IDENTITY
생성 된 가치 에 대한 관심을 멈추십시오 . 무슨 상관이야? 원래 값이 매우 중요한 경우 (대리자로 UNIQUEIDENTIFIER
별도의 테이블에서 생성 될 수 있음)을 사용하십시오 IDENTITY
.
- "초기 삭제"를 사용하도록 아카이브 프로세스를 변경하십시오. 여기서 무언가가 처음에 아카이브 된 것으로 표시되고 나중에 아카이브가 영구적으로 만들어지지 않습니다. 그런 다음 프로세스를 뒤로 이동하려고하면 직접 업데이트를 수행하고 소프트 삭제 플래그를 수정할 수 있습니다.