MySql의 LAST_INSERT_ID () 함수가 정확합니까?


36

INSERT이있는 테이블에 단일 행 을 수행 AUTO_INCREMENT하면 LAST_INSERT_ID()함수를 사용하여 AUTO_INCREMENT해당 행에 저장된 새로운 값 을 반환 하고 싶습니다 .

많은 Microsoft SQL Server 개발자 및 관리자가 의심 할 여지없이 SQL Server ( SCOPE_IDENTITY@@IDENTITY) 의 동등한 기능에 문제 가 없음을 알고 있습니다 .

MySQL 문서 상태를 알고 있습니다.

생성 된 ID는 연결 별로 서버에서 유지 보수 됩니다. 이는 함수가 주어진 클라이언트에 반환 한 값이 해당 클라이언트 AUTO_INCREMENTAUTO_INCREMENT열에 영향을 미치는 가장 최근의 명령문에 대해 생성 된 첫 번째 값 임을 의미 합니다. 다른 클라이언트 AUTO_INCREMENT가 자체 값을 생성 하더라도이 값은 다른 클라이언트의 영향을받지 않습니다 . 이 동작은 각 클라이언트가 다른 클라이언트의 활동에 대한 염려 나 잠금 또는 트랜잭션없이 자신의 ID를 검색 할 수 있도록합니다.

(출처)

심지어 말하기까지 :

여러 클라이언트에서 동시에 LAST_INSERT_ID()AUTO_INCREMENT열을 사용하는 것은 완벽하게 유효합니다.

(출처)

LAST_INSERT_ID()올바른 값을 반환하지 않을 수있는 알려진 위험이나 시나리오가 있습니까?

CentOS 5.5 x64 및 Fedora 16 x64 및 InnoDB 엔진에서 MySQL 5.5를 사용하고 있습니다.

답변:


35

사용할 때 지적하고 싶은 몇 가지주의 사항 LAST_INSERT_ID:

  1. 한 줄짜리 인서트를 언급했습니다. 그러나 다중 행 삽입을 수행하면 LAST_INSERT_ID()삽입 된 첫 번째 행의 값 (마지막이 아님)이 반환됩니다.

  2. 삽입이 실패하면 LAST_INSERT_ID()정의되지 않습니다. 트랜잭션의 자동 롤백 (오류로 인해)에도 마찬가지입니다.

  3. 당신이 성공의 거래에서 삽입을, 당신은 여전히를 발행하는 경우 ROLLBACK, LAST_INSERT_ID()이 롤백 이전 상태로 남아있는 것입니다.

  4. 거기 몇 가지주의 사항 사용할 때 AUTO_INCREMENTLAST_INSERT_ID문 기반 복제에. 첫 번째는 트리거 또는 기능에 사용될 때입니다. 두 번째는 auto_increment 열이 복합 기본 키의 일부이며 키의 첫 번째 열이 아닌 덜 일반적인 시나리오입니다.


7

DTest가 제공 한 답변에서 2 번 포인트를 더 확장하려면 :

내가 사용한 MySQL 버전 에서는 삽입을 수행하려는 각 코드 블록 전에 LAST_INSERT_ID 값 을 명시 적으로 재설정 하는 것이 좋습니다 .

다음과 같이 할 수 있습니다 :

-- initialize the LAST_INSERT_ID to some flag value:
SELECT LAST_INSERT_ID( some_flag_init_value_of_your_choice );
-- perform the insert  
INSERT INTO ttt (ccc) VALUES (vvv);
-- retrieve the id of the inserted row:  
SELECT LAST_INSERT_ID();

위의 일련의 명령문이 실행 된 후에는 실행이 끝날 때 LAST_INSERT_ID가 여전히 "some_flag_init_value_of_your_choice"로 설정되어 있는지 확인하여 삽입이 영향을 미쳤는지 알 수 있습니다.

그렇지 않으면 다음과 같은 문제가 발생할 수 있습니다.

INSERT INTO ttt ( ccc ) VALUES ( 'a' );    -- assume this succeeds.
SELECT LAST_INSERT_ID();                   -- this will return the unique id of the new row with value 'a'.
INSERT INTO ttt ( ccc ) VALUES ( 'b' );    -- assume this FAILS.
SELECT LAST_INSERT_ID();                   -- this will STILL RETURN the unique id of the row with 'a'.

두 번째 삽입이 실패 했기 때문에 LAST_INSERT_ID에 대한 두 번째 호출이 NULL을 리턴하거나 빈 결과 세트 (행 0)를 생성 할 것으로 예상했을 수 있습니다. 여전히 유효한 정수 식별자를 반환한다는 사실 때문에 두 번째 삽입이 실패했을 때 성공했다고 생각하게 할 수 있습니다.

이후의 실패한 삽입 명령문이 마지막으로 성공한 고유 ID를 생성 한 테이블 과 다른 테이블을 대상으로하더라도 LAST_INSERT_ID가 마지막으로 성공한 고유 ID를 계속 유지하고 반복한다고 생각하면 상황이 악화됩니다 . 다시 말해, 테이블 TA에 삽입하고 ID 5를 얻은 다음 TB에 삽입하지만 실패하지만 여전히 5가 표시됩니다.이를 바탕으로 TA에서 새 행을 작성 했다고 생각 합니다. id가 5 이고 TB에 id가 5 인 새로운 행이있는 반면 실제로는 id가 5 인 TB에는 행이 없거나 그러한 행이 존재하지만 실제로는 코드와 관련이 없습니다. 달렸다.


2
우선 last_insert_id()쿼리의 성공 여부를 판단 하기 위해 존재를 사용해서는 안됩니다 . 결국 마지막으로 삽입 된 ID이며 이미 성공했음을 알았을 때 필요한 값을 보유합니다.
Pacerier
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.