본문 바로가기

개발/JAVA

[SPRING] Mybatis에서 다중 insert하기

반응형

ORACLE인 경우 다중 insert


일단 오라클에서는 INSERT ALL 구문으로 한 번에 여러 개의 데이터를 삽입할 수 있다.
관련된 내용은 이전에 올렸던 적이 있다.
https://smile-place.tistory.com/entry/ORACLE-INSERT-ALL-%EA%B5%AC%EB%AC%B8?category=999160

 

[ORACLE] INSERT ALL 구문

오라클에서 여러 번 INSERT를 할 때 INSERT ALL 구문을 이용하면 한 번의 쿼리로 하나의 테이블에 여러 개의 데이터를 삽입하거나 여러 개의 테이블에 한 번에 데이터를 삽입할 수 있다. 하나의 테이

smile-place.tistory.com


Mybatis에서도 INSERT ALL 구문을 활용하면 된다.
여기서 INSERT 해 줄 테이블은 LOGIN_INFO라는 아래의 컬럼을 가진 테이블이다.
* LOGIN_INFO

SITE ID PW


아래와 같은 배열이 있는 json 데이터를 파라미터로 받았다고 가정하자.

{ 
"site": "main", 
"login_data": [ { "id": "test1", "pw": "12345" }, 
{ "id": "test2", "pw": "67890" }, 
{ "id": "test3", "pw": "1234567890" } ] 
}


위의 데이터를 Map에 담아주는데 배열의 경우 LIST에 담아서 Map에 다시 담아준다.
아래와 같이 Controller를 작성해주면 된다.

@RequestMapping(value="URL이 들어가는 자리")
public void MemberInfo( @RequestBody HashMap<String, Object> params ) throws Exception {
//데이터를 담아줄 map 생성 
HashMap< String , Object > map = new HashMap< String , Object >(); 
//일반 파라미터는 map에 그대로 
put map.put( "site" , params.get( "site" ) );
//배열 파라미터는 list에 put하고 그 list를 map에 put 
List<Map<String,Object>> memberList = (List<Map<String, Object>>) params.get("login_data"); 
map.put( "memberList" , memberList); }


여기서 site 파라미터 값은 그대로, id와 pw 값은 각각 다르게 여러 번, 이 경우에는 배열의 길이가 3개이므로 3번 insert 해주는 경우 mapper에서 다음과 같이 쓸 수 있다.

<update id="insertLoginInfo" parameterType="java.util.HashMap"> 
<foreach collection="memberList" item="item" separator=" " open="INSERT ALL" close="SELECT * FROM DUAL"> 
INTO LOGIN_INFO(SITE, ID, PW) VALUES(
#{site}, #{item.id}, #{item.pw}
) 
</foreach> 
</update>


주의해야 하는 점은 실제로는 INSERT를 수행하지만 이 방법을 쓰는 경우 UPDATE 태그를 써야한다는 것이다.

간단하게 foreach 태그를 보면
collection : map에 담겨있는 list의 이름
item : 반복문 변수(자바 for문에서의 i같은 역할)
separator : 반복될 때 구분값
open : foreach문 안의 구문의 맨 앞에 붙는 것
close : foreach문 안의 구문의 맨 뒤에 붙는 것

foreach문 안에서 배열에서 반복되는 값 앞에 item에서 설정한 이름을 붙여준다.
INSERT ALL의 경우 서브쿼리가 필요하므로 close부분이 꼭 필요하다.

테이블에는 결과적으로 아래와 같이 데이터가 삽입된다.

SITE ID PW
main test1 12345
main test2 67890
main test3 1234567890


하지만 이 때 반복해서 삽입하는 테이블에 시퀀스가 있고 그 시퀀스가 PK거나 UNIQUE 제약조건이 있다면 이 방법은 사용할 수가 없다.

이럴 때는 INSERT ALL 대신 UNION ALL 구문을 사용해서 INSERT 해줘야 한다.

이번에 INSERT 해 줄 테이블은 시퀀스를 넣을 컬럼을 추가하여 아래와 같다고 가정하자.
* LOGIN_INFO

MEMBER_NUM SITE ID PW


시퀀스는 마이바티스에서 설정하면 되기 때문에 파라미터로 받은 json 데이터와 Controller는 위와 같이 작성해주면 된다.
시퀀스명은 MEMBER_NUM_SEQ이라고 가정하자.
mapper 부분은 아래와 같이 작성해준다.

<insert id="insertLoginInfo" parameterType="java.util.HashMap"> 
INSERT INTO LOGIN_INFO(MEMBER_NUM, SITE, ID, PW) 
SELECT MEMBER_NUM_SEQ.NEXTVAL, A.* 
FROM ( 
<foreach collection="memberList" item="item" separator="UNION ALL "> 
SELECT #{site} AS SITE, #{item.id} AS ID, #{item.pw} AS PW FROM DUAL 
</foreach> 
) A 
</insert>


아까 INSERT ALL 구문과는 다르게 UNION ALL의 경우 insert 태그를 사용해준다.
시퀀스 부분을 foreach문 바깥에 빼주고 작성해주는데
아까와는 다르게 foreach에는 collection, item, separator 항목만 써주면 된다.
한 개 이상이 반복될 수 있으므로 separator에는 UNION ALL을 써서 반복적으로 사용할 수 있게 한다.
ALL 뒤에 띄어쓰기가 있다는 것도 빼먹으면 안된다.

테이블에는 결과적으로 아래와 같이 데이터가 삽입된다.

MEMBER_NUM SITE ID PW
1 main test1 12345
2 main test2 67890
3 main test3 1234567890


MYSQL인 경우 다중 insert
MYSQL에서 다중 insert하는 경우에는 ORACLE과는 문법이 다르기 때문에 mapper 부분을 조금 다르게 작성해야 한다.
ORACLE보다는 MYSQL이 더 간단하게 해결할 수 있다.

json으로 받는 파라미터, Controller부분은 위의 정보와 동일하다는 전제하에 LOGIN_INFO라는 테이블에 insert를 해보자.

* LOGIN_INFO

SITE ID PW


MYSQL에서는 INSERT INTO 테이블명(컬럼1, 컬럼2...) VALUES (값1, 값2...), (값1-1, 값2-1...) 의 방식으로 다중 INSERT가 가능하기 때문에 Mybatis 작성도 위와 같이 해주면 된다.

mapper 부분은 아래와 같은 형식으로 작성해준다.

<insert id="insertLoginInfo" parameterType="java.util.HashMap"> 
INSERT INTO LOGIN_INFO(SITE, ID, PW) VALUES 
<foreach collection="memberList" item="item" separator=" , "> 
(#{site}, #{item.id}, #{item.pw}) 
</foreach> 
</insert>


결과적으로 테이블에는 아래와 같이 데이터가 삽입된다.

SITE ID PW
main test1 12345
main test2 67890
main test3 1234567890

 

반응형