2013-03-25 3 views
0

C#에서 두 개의 스레드를 만들고 두 개의 별도 함수를 병렬로 호출하고 있습니다. 두 함수 모두 XYZ 테이블에서 마지막 ID를 읽고 값 ID + 1 인 새 레코드를 삽입합니다. 여기서 ID 열은 기본 키입니다. 두 함수를 모두 실행할 때 기본 키 위반 오류가 발생합니다. 두 함수 모두 다음과 같은 쿼리를 가지고 있습니다 :SQL Server 2008의 기본 키 위반 오류

insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

두 함수 모두 한 번에 값을 읽고 같은 값으로 삽입하려고합니다. 어떻게하면이 문제를 해결할 수 있습니까?

+0

음 :

는 내가 틀렸다면 그래서 희망 누군가가 편집을 제안합니다, 너무 자주 이러한 기능을 사용하지 않는,하지만 당신은 이들 중 하나를 원하는 Java는 여러 스레드가 서로 간섭하지 않도록 동기화 된 키워드를가집니다. C#의 유사 구조에 대한 멀티 스레딩 링크를 찾아 보시기를 권합니다. –

+0

@ChetterHummin 아니요, 문제는 응용 프로그램에 삽입 할 ID를 알아 내려고 시도하고 있다는 것입니다. 예, 그는 또한 ID 변수를 공유하고 동기화 할 수는 있지만 데이터베이스 동기화 문제를 막지는 못합니다. 예를 들어, 자신의 테이블에 자신의 공유 변수를 사용하지 않는 제 3자가 삽입하는 문제를 생각해보십시오. 그렇다면 그는 여전히 같은 문제가 있습니다. – KyleM

+0

@KyleM 설명해 주셔서 감사합니다! 위의 –

답변

2

데이터베이스에서 사용자의 ID 선택을 처리하도록하십시오. 위의 코드에서 분명히 알 수있는 것은 자동 증가 정수 ID 열입니다.이 정수 열은 데이터베이스에서 확실히 처리 할 수 ​​있습니다. 그래서 제대로 대신 현재 삽입 문의 테이블을 설정,이 작업을 수행 : 마지막으로

alter table your_table modify column you_table_id int(size) auto_increment 

: 데이터베이스 테이블이 이미 설정되어있는 경우

insert into XYZ values('Name') 

난 당신이 유사한 문을 발행 할 수 있습니다 생각 , 어떤 해결책이든지 (주석 섹션에서 설명한 것처럼 테이블 스키마를 편집 할 수없는 경우를 포함하여) 적절한 것이 아니라면 주석에 제안 된 다른 사용자 중 한 명으로 할 수 있고 동기화 된 메소드를 만들어 찾을 수 있습니다 다음 ID. 기본적으로 int를 반환하는 정적 메서드를 만들고 해당 정적 메서드에서 select id 문을 실행 한 다음 반환 된 결과를 사용하여 다음 레코드를 테이블에 삽입합니다. 이 방법은 성공적인 삽입을 보장하지 않으므로 (외부 응용 프로그램이 같은 테이블에 삽입 할 수 있기 때문에) 예외를 catch하고 실패시 다시 시도해야합니다.

+0

쿼리 예입니다. 사실 50 개 이상의 필드와 기본 키 필드는 자동 증가가 아닙니다. 고유 한 값을 명시 적으로 삽입해야합니다. – Irappabi

+0

@ user1365604 그런 다음 기본 키의 작동 방식을 설명해야합니다. 지금까지 설명한 내용에서 가장 확실하게 증가 열이어야합니다. – KyleM

+0

@ user1365604 명시 적으로 삽입해야하는 이유는 무엇입니까? 왜 데이터베이스 테이블의 디자인을 자동 증가로 수정할 수 없습니까? '변경'진술이 무엇인지 아십니까? – KyleM

2

ID 열을 "ID"열로 설정하십시오.

insert into XYZ values('Name') 

당신이 열을 만든 후 신원로 열을 변경하는 ALTER 테이블을 사용할 수 없다는 생각 : 그런 다음으로 쿼리를 실행할 수 있습니다. Managament Studio를 사용하여이 열을 Identity로 설정하십시오. 테이블에 많은 행이있는 경우 실제로는 새 테이블에 데이터를 복사하므로 (테이블 재 작성을 수행 할 것이므로) 장기 실행 프로세스 일 수 있습니다.

대부분의 경우 Managament Studio에서이 옵션을 사용할 수 없습니다. 도구 -> 옵션 -> 디자이너를 열고 테이블 크기에 따라 "테이블 재 작성이 필요한 변경 사항 저장 금지"옵션을 선택 해제하려면 시간 제한도 설정해야합니다. 그 시간 동안 테이블이 잠길 것입니다.

0

이러한 문제에 대한 해결책은 일종의 시퀀스를 사용하여 ID를 생성하는 것입니다.

예를 들어, SQL 서버에서 아래의 명령을 사용하여 시퀀스를 만들 수 있습니다

CREATE SEQUENCE Test.CountBy1 
    START WITH 1 
    INCREMENT BY 1 ; 
GO 

그런 다음 C#으로, 당신은 시험에서 다음 값을 검색 할 수 있으며 삽입하기 전에 ID에 할당합니다.

+1

시퀀스는 SQL Server 2012에서만 사용할 수 있습니다. OP는 그 기능이없는 2008 년을 사용하고 있습니다. – Gabe

+0

감사합니다. 게이브, 그걸 몰랐습니다. 아래 게시물은 "IDENTITY"열을 제안합니다. http://stackoverflow.com/questions/7238816/cant-create-sequence-in-sql-server-2008 –

0

더 높은 것 같아요. transaction isolation level 이상 locking입니다.,

-- specify the strictest isolation level 
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

또는

-- make locks exclusive so other transactions cannot access the same rows 
insert into XYZ values((SELECT max(ID)+1 from XYZ WITH (XLOCK)),'Name') 
+0

나는 downvote를 이해하지 못한다. 높은 트랜잭션 격리 수준이 이것을 도울 수있다. IDENTITY를 사용하는 것이이 문제에 대한 더 나은 해결책입니다. –

+0

ReReadable과 같은 격리 수준이 있다고 생각합니다. MSDN을 확인해야하지만 신원 열이 더 좋을 것이라고 생각합니다. – Greg

+0

@ 그렉 : 사용할 수있는 수준을 보려면 내 대답에서 "트랜잭션 격리 수준"링크를 클릭하십시오. 당신은 정체성 칼럼이 더 좋을 것이라는 것은 맞지만 이미 2 가지 다른 대답이 있습니다. 또한 식별 열은 열이 정수 * 일 때만 작동하며 스키마를 제어 할 수 있습니다 * 및 * 열을 특정 값으로 설정할 필요가 없습니다. – Gabe