배치 개발하다가 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/
'Back-end > Spring' 카테고리의 다른 글
[IntelliJ 오류] invalid source release, A JNI error has occurred (0) | 2023.03.18 |
---|
댓글