본문 바로가기
Back-end/Spring

[Spring Batch]TransientDataAccessResourceException

by blogsy 2023. 11. 26.

배치 개발하다가 Error 발생했습니다.

 

사실 배치에만 해당하는 에러는 아니고 Mybatis 관련 에러입니다.

글을 Spring batch로 분류한 이유는 해당 에러를 검색해보시면 알겠지만 batch 개발 시 자주 마주칠 수 있는 에러라서..

 

org.springframework.dao.TransientDataAccessResourceException: Cannot change the ExecutorType when there is an existing transaction

 

위와 같은 에러입니다.

 

"존재하는 트랜잭션이 있어 ExecutorType(실행자의 타입)을 변경할 수 없다"

 

저는 Chunk-oriented Processing 방법을 사용해서 Job을 개발하는 중 해당 Error가 발생했습니다.

Reader에서 MybatisPagingItemReader를 이용해 데이터를 조회하고

Writer에서는 mapper를 이용해 데이터를 조회하고 쓰도록 개발했습니다.

 

MyBatisPagingItemReader:  ExecutorType.BATCH

Mapper:  ExecutorType.SIMPLE

 

위와 같이 ExecutorType이 달라서 발생하는 오류였습니다.

 

Spring batch 프로젝트 진행시 mybatis 사용시 MyBatisBatchItemWriter 를 사용하며 MyBatisBatchItemWriter는 내부적으로 SessionFactory 를 전달 받아 SesstionTemplate 생성시 실행자(executor)를 BATCH 로 생성한다.
그렇기 때문에 문제 reader 또는 writer 를 커스텀할 경우 Interface Mapper에 를 주입받아 처리 하는 경우 SesstionTemplate를 생성하게 되는데 이때 mybatis config 를 기본설정으로 사용한다면 실행자(executor)가 SIMPLE로 생성된기 때문에 같은 트랙젝션 내에서 동일한 SqlSesstionFactory는 다른 실행자를 지원하지 않아 에러가 발생한다.

- 같은 트랙젝션 안에서는 동일한 SqlSesstionFactory는 동일한실행자(executor)만 지원한다.

ref:
https://medium.com/@sindepal/org-springframework-dao-transientdataaccessresourceexception-317817a695c9

 

=> MyBtisBatchItemReader도 해당됨

 

처리 방법은 여러가지인데 제가 찾아봤을 때 가장 간단한 방법은 MyBatisCursorItemReader를 사용하는 걸로 보입니다.

- MyBatisCursorItemReader는 실행자(executor)를 SIMPLE로 설정된다.
- MyBatisPagingItemReader는 실행자(executor)를 BATCH로 설정된다.
- MyBatisBatchItemWriter는 실행자(executor)를 BATCH로 설정된다.

 

저의 경우에는 AbstractPagingItemReader를 extends하여 CustomMyBatisPagingItemReader 만들어 처리했습니다.

실제 페이지에서 데이터를 읽는 doReadPage()를 Override해서 ExecutorType을 Simple로 지정해주면 됩니다.

 

// CustomMyBatisPagingItemReader.java

public class CustomMyBatisPagingItemReader extends AbstractPagingItemReader<Product> {
    @Override
    protected void doReadPage(){
        if(sqlSessionTemplate == null){
            sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.SIMPLE);
        }
        // . . .
    }
}

 

 

우아한형제들 기술 블로그를 참고했고, 링크는 하단에 남겨두겠습니다.

 

 

* 참고
mybatis 내부적으로 3가지 실행자(executor)를 지원
1. SIMPLE (디폴트) :
  - 특별히 하는 것이 없다.
  - 구문 실행마다 새로운 PreparedStatement를 생성함
2. REUSE :
  - PreparedStatement를 재사용한다.
3. BATCH :
  - 실행자는 구문을 재사용하고 수정을 배치처리 ( 대용량 처리 )
  - 중간에 select가 실행될 경우 필요하다면 경계를 표시함

 

 

 

참고: https://techblog.woowahan.com/2662/

 

Spring Batch와 Querydsl | 우아한형제들 기술블로그

{{item.name}} Spring Batch와 QuerydslItemReader 안녕하세요 우아한형제들 정산시스템팀 이동욱입니다. 올해는 무슨 글을 기술 블로그에 쓸까 고민하다가, 1월초까지 생각했던 것은 팀에 관련된 주제였습

techblog.woowahan.com

 

댓글