https://royzero.tistory.com/26
RDB에서 TABLE에 INSERT를 할 때 기본키(PK, Primary Key)를 꼭 지켜줘야 하는 경우가 많습니다.
MariaDB나 MySQL등에서는 Auto Increasement를 활용하는 경우가 많지만, Oracle에서는 이 Auto Increasement를 제공하지 않죠.
흔히 MyBATIS를 사용할때, INSERT 하는 방식에는 총 3가지 정도 아이디어를 낼 수 있습니다.
PK SQL과 INSERT SQL을 만들고 호출 하는 방법
INSERT를 SELECT로 만드는 방법
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를 다른 곳에서 사용하고 있는 경우가 있을 수 있기 때문에 향후에 쿼리문을 수정하거나 하는 경우, 영향도 분석이 더욱 어려워질 수 있습니다.)