0. 개요
MyBatis를 쓰면서 INSERT된 행의 PK를 획득해야할 일이 자주 있습니다.
이럴때 사용하는 방법이 두 종류인데요, selectKey구문과 insert 구문의 속성인 useGeneratedKeys입니다.
이중 하나가 동시성 이슈가 있다는 말을 들어서 찾아보게 되었습니다.
1. SelectKey
<insert id="..." parameterClass="..." >
INSERT INTO...
<selectKey resultType="long" order="AFTER" keyProperty="tid">
SELECT LAST_INSERT_ID()
</selectKey>
</insert
보통 INSERT 쿼리문 내부에 selectKey블럭을 입력해서 사용합니다.
속성값들은 아래와 같은 의미를 가지고 있습니다.
- result type : 반환할 pk의 타입
- order : SELECT LAST_INSERT_ID()를 언제 실행할지 결정(감싼 쿼리문의 전, 후)
- keyProperty : 반환받을 PK가 매핑될 속성을 지정 (ex - PK칼럼이 tid여도, id로 받을수 있음)
반환받은 PK는 쿼리를 수행할 때 parameter로 사용한 객체에 매핑됩니다.
keyProperty속성을 명시했다면 해당 속성에 매칭되며, keyProperty속성을 명시하지 않았다면 테이블 PK속성명으로 매핑됩니다.
- parameter가 Map인 경우, key(PK 속성명)-value 쌍으로 저장
- 커스텀 객체를 사용할 경우 해당 객체의 속성에 매핑되며, 프로퍼티가 없다면 매핑x
2. useGeneratedKeys
<insert id="insertQna" useGeneratedKeys="true" keyProperty="seq">
//...
</insert>
insert 구문의 속성에 입력해 사용합니다.
LAST_INSERT_ID()와 같은 쿼리를 직접 실행하지 않고, 데이터베이스가 자동으로 생성한 키 값을 반환하도록 합니다.
반환받은 PK는 쿼리를 수행할 때 parameter로 사용한 객체에 매핑됩니다.
keyProperty속성을 명시했다면 해당 속성에 매칭되며, keyProperty속성을 명시하지 않았다면 테이블 PK속성명으로 매핑됩니다.
- parameter가 Map인 경우, key(PK 속성명)-value 쌍으로 저장
- 커스텀 객체를 사용할 경우 테이블의 PK와 동일한 프로퍼티에 매핑되며, 동일한 프로퍼티가 없다면 매핑x
3. 동시성 이슈
두 구문은 자동으로 생성된 키 값을 가져와서 매핑하는 것으로 목적은 같습니다.
하지만 실행 방법은 상이합니다.
그렇다면 어느쪽이 동시성 이슈가 생길 수 있을까요? 바로 selectKey입니다.
selectKey는 SELECT LAST_INSERT_ID()의 결과를 반환하기 때문에, 싱글서버 싱글스레드에서 사용하면 안전하겠지만,
멀티 인스턴스, 멀티 어플리케이션 서버에서는 안전하지가 않습니다.

SELECT 쿼리를 수행해 PK를 반환하기 떄문에 위 사진처럼 다른 쿼리와 충돌이 발생할 수 있습니다.
반면, useGeneratedKeys 속성은 데이터베이스가 자동으로 생성한 키 값을 반환하도록 하기 때문에,
INSERT 쿼리 실행 후 바로 키 값을 받아올 수 있습니다.
따라서, useGeneratedKeys 속성을 사용하는 것이 selectKey 구문보다 동시성 이슈가 적고, 더 안전하게 키 값을 가져올 수 있습니다.
'Database' 카테고리의 다른 글
MySQL] 조인(Table join) 종류 (0) | 2023.01.25 |
---|---|
Mybatis) 조건문 if-else -> choose-when-otherwise (0) | 2022.08.21 |
[MySQL] ON DUPLICATE KEY UPDATE [짧] (0) | 2022.05.23 |
[MySQL] 복합키 설정하기 [짧] (0) | 2022.05.23 |
Procedure 기본 (0) | 2022.05.03 |