[MyBATIS] Primary Key를 Insert하기 위한 SelectKey

Dana's Log·2023년 1월 5일
0

https://royzero.tistory.com/26

RDB에서 TABLE에 INSERT를 할 때 기본키(PK, Primary Key)를 꼭 지켜줘야 하는 경우가 많습니다.

MariaDB나 MySQL등에서는 Auto Increasement를 활용하는 경우가 많지만, Oracle에서는 이 Auto Increasement를 제공하지 않죠.

흔히 MyBATIS를 사용할때, INSERT 하는 방식에는 총 3가지 정도 아이디어를 낼 수 있습니다.

  1. PK SQL과 INSERT SQL을 만들고 호출 하는 방법

  2. INSERT를 SELECT로 만드는 방법

  3. SelectKey 구문을 활용하는 방법

만약 아래와 같은 테이블이 있다고 가정한다면

CREATE TABLE TB_BOARD (
    BBS_SEQ INT NOT NULL,
    BBS_TITLE VARCHAR(100) NOT NULL,
    BBS_CONT TEXT,
    PRIMARY KEY (BBS_SEQ)
);
public class Board {
    private int bbsSeq;
    private String bbsTitle;
    private String bbsCont;
    
    public int getBbsSeq(){
        return bbsSeq;
    }
    public void setBbsSeq(int bbsSeq){
        this.bbsSeq = bbsSeq;
    }
    public String getBbsTitle(){
        return bbsTitle;
    }
    public void setBbsTitle(String bbsTitle){
        this.bbsTitle = bbsTitle;
    }
    public String getBbsCont(){
        return bbsCont;
    }
    public void setBbsCont(String bbsCont){
        this.bbsCont = bbsCont;
    }
}

PK SQL과 INSERT SQL을 만들고 호출 하는 방법

<select id="getKey" returnType="int">
    SELECT IFNULL(MAX(BBS_SEQ), 0) + 1
      FROM TB_BOARD
</select>

<insert id="insertBoard" parameterType="Board">
    INSERT INTO TB_BOARD (BBS_SEQ, BBS_TITLE, BBS_CONT)
                  VALUES (#{bbsSeq}, #{bbsTitle}, #{bbsCont})
</insert>

먼저 getKey를 호출해서 int값을 Insert할 Board의 bbsSeq에 넣어주고 insertBoard에 해당 Board를 넣어주는 방식으로 가능합니다.

다만, 이렇게 호출 할때, Transaction을 잘 확인하지 않으면 중복의 오류가 발생할 수 있기 때문에, 호출하는 레벨이 한 개의 트랜잭션에서 수행되고 있는지 고려해야 합니다. (자주 하는 실수)

INSERT를 SELECT로 만드는 방법

<insert id="insertBoard" parameterType="Board">
  INSERT INTO TB_BOARD (BBS_SEQ, BBS_TITLE, BBS_CONT)
  SELECT IFNULL(MAX(BBS_SEQ), 0) + 1
       , #{bbsTitle}
       , #{bbsCont}
    FROM TB_BOARD
</insert>

이렇게 하면, 에러율이 많이 줄어들기는 하지만, 잘못된 Query로 결과값이 2개 이상인 경우 중복의 오류(현재 쿼리에서는 MAX라는 그룹으로 묶인 단일 컬럼이라 중복이 없지만)가 발생할 수도 있습니다.

SelectKey 구문을 활용하는 방법

<insert id="insertBoard" parameterType="Board">
  <selectKey resultType="string" keyProperty="bbsSeq" order="BEFORE">
      SELECT IFNULL(MAX(BBS_SEQ), 0) + 1
        FROM TB_BOARD
  </selectKey>
  INSERT INTO TB_BOARD (BBS_SEQ, BBS_TITLE, BBS_CONT)
                VALUES (#{bbsSeq}, #{bbsTitle}, #{bbsCont})
</insert>

위와 같이 사용시, 한 개의 트랜잭션 내에서 수행되며, 호출을 관리하기가 편리합니다. (만약 첫 번째의 경우 getKey를 다른 곳에서 사용하고 있는 경우가 있을 수 있기 때문에 향후에 쿼리문을 수정하거나 하는 경우, 영향도 분석이 더욱 어려워질 수 있습니다.)

profile
다나로그

0개의 댓글