본문 바로가기
개발 및 잡담/JAVA

[JAVA] 효율적인 트랜잭션? (feat. 마이바티스 foreach insert/update +시퀀스)

by 아는게 없어 항상 몰라 2023. 9. 7.

개요

CRUD 코드를 짜거나 보면 보통

// List<Map<String,Object>> list 라는 녀석이 넘어왔다고 가정하자

for (Map<String,Object> map : list){
    // ~ 업무로직 ~
    // ~ 업무로직 ~
    // ~ 업무로직 ~
    
    // 트랜잭션
    insert(map);
}

라는 느낌으로 작성을 했고 작성된 것도 많이 봤다.

 

 

 

트랜잭션이 발생할 때마다 웹에서 db로 왔다 갔다 작업을 하는 것을 우리는 알고있다.

이 점을 염두하고 생각을 해보니까 list가 10건 30건 정도면 다행이지만 천단위를 넘어서 수만건의 데이터가 넘어온다면?

웹에서 db로 왔다갔다 하는 작업만 수만번을 반복해야되는 아주 비효율적인 상황이 발생한다.

 

 

효율적인 트랜잭션?

그렇다면 좀 더 효율적으로 어떻게 짜야될까? 생각해보니

건마다 보내는 것이 아닌 '리스트에 담고 50건, 100건이 쌓이면 그때 리스트를 넘겨 트렌잭션을 일으키는건?' 이라는 생각을 했다.

 

// 똑같이 List<Map<String,Object>> list 라는 녀석이 넘어왔다고 가정하자

// 트렌잭션에 사용할 객체생성
List<Map<String,Object>> tempList = new ArrayList<>();
Map<String,Object> tempMap = new HashMap<>();

for (int i=0; i<list.size(); i++){

    tempMap = list.get(i);

    // ~업무로직~
    // ~업무로직~
    // ~업무로직~
    
    tempList.add(tempMap);

    // 50건이 쌓이면 트랜잭션
    if (tempList.size() == 50){
        insert(tempList);
        tempList = new ArrayList<>(); // tempList초기화
    } else {
    	// tempList가 50건이 안쌓였지만 for문이 끝난경우
    	if (i == list.size()-1){
            insert(tempList);
        }
    }
    
    tempMap.clear(); // tempMap 초기화
}

 

이런 느낌으로 50건 100건이 쌓이면 그때 리스트를 넘겨 트랜잭션을 한 번만 일으키는 방식을 사용해보니 잘 동작한다.

뿌듯하다. 앞으로 이런 방식으로 짜야겠다.

 

 

 

마이바티스 foreach

해당 로직을 사용하기 위해 mapper.xml을 좀 수정해줘야된다. 

 

1. insert

<insert id="아이디" parameterType="java.util.List" >
    INSERT INTO 테이블명(
          컬럼1
        , 컬럼2
        , 컬럼3
    ) VALUES 
    <foreach collection="list" item="item" separator=",">
    (
          #{item.키1}
        , #{item.키2}
        , #{item.키3}
    )
    </foreach>
</insert>

요런 느낌으로 foreach를 추가해줘야된다.

 

"어? 저는 insert 할 때 시퀀스를 사용하거든요? 근데 foreach 적용하니까 에러나요!!"

    <update id="아이디" parameterType="java.util.List">
        INSERT INTO 테이블명 (
        	컬럼1,
        	컬럼2,
        	컬럼3
        ) 
        SELECT 시퀀스명.NEXTVAL
             , T.*
          FROM (
          	<foreach collection="list" item="item" index="index" separator="union all">
                SELECT  #{item.키1},
                        #{item.키2}
                  FROM  DUAL
	        </foreach>
               ) T
    </update>

컬럼1이 시퀀스를 사용하는 컬럼이라고 가정하면, 요런 느낌으로 작성하자

 

 

 

2. update

<update id="아이디" parameterType="java.util.List">
    <foreach collection="list" index="index" item="item" separator=";" open="DECLARE BEGIN" close="; END;">
        UPDATE 테이블명 
           SET 컬럼1 = #{item.키1},
               컬럼2 = #{item.키2},
               컬럼3 = #{item.키3}
         WHERE 컬럼4 = #{item.키4}
    </foreach>
</update>

업데이트는 요런식으로 DECLARE BEGIN END 구조를 사용하자

댓글