PostgreSQL은 Returning이라는 기능으로 DML처리 시 변경되는 컬럼의 값을 리턴받을 수 있다.
INSERT INTO post (title, content)
VALUES ('Returning', 'PK값을 리턴받을 수 있다.')
RETURNING post_id;
-- 결과
post_id
--------
9
이 기능을 통해서 MyBatis의 태그를 대체해서 사용할 수 있다.
MySQL에서 사용했던 방법과 PostgreSQL의 사용방법을 비교하여 확인해본다.
MyBatis 에서 사용하기
비즈니스 로직을 처리할 때 부모테이블이나 Insert 되는 테이블의 auto_increment되는 테이블의 PK 값을 알아야 할 필요가 있어서 MyBatis의 SelectKey 기능을 사용한다.
PostgreSQL은 SelectKey 기능을 사용하지 않고 Insert되는 PK의 시퀀스 값을 얻어올 수 있다.
MySQL 사용 방식
<insert id="save">
INSERT INTO
table_ex (
col1,
col2,
created_at
)
VALUES (
#{col1},
#{col2},
now(),
<selectKey keyProperty="tableId" order="AFTER" resultType="Long">
SELECT
LAST_INSERT_ID()
</selectKey>
<insert>
MySQL에서 Insert 되는 테이블의 PK 값을 얻기 위해서 keyProperty 를 통해서 리턴될 키를 지정해주면, 프로퍼티와 일치하는 키값으로 Auto_increment된 시퀀스 값이 매핑되어 들어가있게 된다.
PostgreSQL Returning 사용
PostgreSQL 에서는 Returning 기능을 통해서 DML로 수정되는 테이블의 값을 리턴받을 수 있다.
<!-- 에러
<insert id="savePost" >
INSERT INTO
post (
title,
CONTENT
)
VALUES (
#{title},
#{content})
RETURNING post_id
</insert> -->
<select id="savePost" resultType="Integer">
INSERT INTO
post (
title,
CONTENT
)
VALUES (
#{title},
#{content})
RETURNING post_id
</select>
<select id="updatePost" resultType="HashMap">
UPDATE test.POST SET
title = #{title},
content = #{content},
updated_at = now()
WHERE
post_id = #{postId}
RETURNING title, post_id
</select>
주의할 점은 insert 문을 사용할 때 보통 명시적인 insert 태그를 사용하는데 <insert>, <update>, <delete> 태그와 같이 DML을 위한 태그는 resultType이 없고, 기본적으로 DML로 처리된 row를 리턴하기 때문에 Returning 기능과 DML 전용 태그를 사용하게 되면 기존 리턴되는 처리되는 ROW 수의 값과 충돌이나서 -1을 리턴하게 된다.
Returning 기능은 MyBatis의 <select> 태그로 사용해야 하며, PK값만 받을 수 있는 것이 아닌 테이블의 전체 컬럼 중 원하는 컬럼을 선택하여 리턴할 수 있다.
<selectKey>와 다른점은 값을 리턴받는 것이기 때문에 selectKey처럼 DML이 처리되고 KeyProperty로 지정한 파라미터로 값이 자동 주입되는 것이 아닌, resultType의 리턴 값을 통해서 받아야 한다.
@Test
void savePostTest() {
Map<String, Object> param = new HashMap<>();
param.put("title", "리턴 값 테스트");
param.put("content", "Return Value Test");
param.put("post_id", null);
Integer result = customService.savePost(param);
log.info("param : {}", param);
log.info("savePost ReturnValue : {}", result);
assertThat(result).isNotNull();
}
/* 결과
param : {post_id=null, title=리턴 값 테스트, content=Return Value Test}
savePost ReturnValue : 8
*/
테스트 결과를 확인하면 주입된 파라미터에는 값이 들어오지 않았고 리턴 값은 시퀀스 값이 나타난 것을 확인할 수 있다.
select 문에 사용하면 조회 쿼리와 리턴 값이 충돌나기 때문에 사용하면 안된다.
참조
'Database' 카테고리의 다른 글
| [PostgreSQL] Invalid Transaction Termination 에러 (0) | 2024.04.18 |
|---|