Spring과 MyBatis연동시 배치를 처리할 경우가 있다. 한꺼번에 인서트나 업데이트가 필요한 경우있다. 이 때 SqlSession을 반복적으로 처리하는 방법과 xml에서 foreach를 처리하는 방법이 있다.
먼저 DB는 Mariadb(MySql)을 기준으로 설명한다. test_book_origin 테이블이 있다. 이 테이블에는 originPrice 라는 컬럼이 있고, 각각의 값들이 있다. originPrice 값을 일괄적으로 0으로 변경해주는 배치를 만들어본다. 물론 쿼리에서 한번에 할 수 있으나, 여기선 배치를 해보기위해 테스트한다.
1.SqlSession에서 배치처리
applicationContext.xml에 다음을 추가한다.
그리고 mybatis용 SQL처리 xml에는 아래와 같이 일반적으로 작성한다.
그리고 나서 DAO 클래스에서는 다음과 같이 처리한다.
TestBook은 test_book_origin의 엔티티 클래스이다. Controller클래스에서 executeUpdateBatch를 만들었는데 test_book_origin 테이블의 레코드를 읽여들여서 originPrice를 0으로 업데이트하는 메소드이다. 여기서는 batchType=1(SqlSession방식)로 실행된다.
Main클래스에서 호출하는 executeUpdateBatch 메소드이다.
실제로 위 메소드를 실행한 소요시간이다. (10만건 업데이트)
이것을 이번에는 xml에서 foreach 처리로 바꾸어보자.
2. XML에서 foreach구문으로 배치처리
sql구문처리하는 xml소스를 보자.updateBatch2 메소드가 추가된다.
bookID를 IN으로 처리하고 그 부분을 foreach로 처리한다. collection은 list라는 맴변수이고 거기에는 TestBook의 클래스들이 리스트로 담겨져있다. 그러므로 item은 testBook으로 하면 #{testBook.bookID}로 접근해야 한다. DAO클래스를 보자.
DAO클래스는 간단하게 작성되었다.(Serive 클래스도 같다) 중요한 것은 실제로 호출하는 Controller클래스이다.
즉, Map파라미터에 list라는 값을 넣고 실제로 collection값을 넣어야 한다. 그래서 foreach구문에 collection값에 map에 할당된 변수를 넣어주고, item에 변수를 지정하여 그 값으로 반복처리하는 것이다.
이렇게 해서 실행시켜보면 아래과 같은 속도가 나왔다. (10만건 업데이트)
무려 9배의 속도가 단축되었다. (어찌보면 당연한다 한번에 쿼리로 일괄처리하는 것이 더 효율적인 것이다)
인서트부분도 같은 10만건에 데이트를 다른 테이블에 인서트하는 테스트를 해보았는데 역시 같은 수준의 속도가 나왔다.
SqlSession 배치 : 75(ms) -> XML에서 Foreach 처리 : 12(ms)
MySQL, MariaDB에서는 대량 부분을 다음과 같이 쿼리로 적용할 수 있다. 즉 VALUES에 해당되는 부분만 반복해서 넣어주면 된다.
따라서 VALUES 부분만 foreach로 처리해주면 된다.
()부분이 반복되므로 open, close는 비워주고, separator만 “,”로 처리하면 된다. 가급적 배치처리에는 Mybatis의 foreach를 사용하는 것이 훨씬 효율적이다.