TroubleShooting

TransientDataAccessResourceException

KJihun 2025. 6. 2. 11:41
728x90

 

문제

 

Spring batch 사용 시 Read 방식을 List로 구현하였을 때에는 정상적으로 동작이 수행되었다
이후, read방식을 paging 으로 변경 후 quartz가 실행되었을 때, TransientDataAccessResourceException 발생하였다.

 

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

 

 

 

문제의 본질

mybatis는 내부적으로 3가지 실행자(executor)를 지원한다.

  • SIMPLE (디폴트) : 구문 실행마다 새로운 PreparedStatement를 생성
  • REUSE : PreparedStatement를 재사용
  • BATCH : 실행자는 구문을 재사용하고 수정을 배치처리

 

1. MyBatisPagingItemReader가 내부적으로 ExecutorType.BATCH로 작동한다.
2. 일반적인 Mapper는 ExecutorType.SIMPLE 기반이다.

3. MyBatis는 하나의 트랜잭션 안에서 서로 다른 ExecutorType을 허용하지 않는다.
4. 같은 트랜잭션에서 BATCH와 SIMPLE을 호출하여 TransientDataAccessResourceException 가 발생한 것이었다.

reader에서 .BATCH 호출
writer에서 .SIMPLE(Mapper) 호출



  

 

해결

별도 SqlSessionFactory 구성

 

@Configuration
public class MyBatisConfig {
    
    // 일반 Mapper용 SqlSessionFactory (SIMPLE)
    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        ....
        return factoryBean.getObject();
    }
    
    // MyBatisPagingItemReader용 SqlSessionFactory (BATCH)
    @Bean("batchSqlSessionFactory")
    public SqlSessionFactory batchSqlSessionFactory(DataSource dataSource) throws Exception {
       ....
        return factoryBean.getObject();
    }
    
    // MyBatisPagingItemReader 설정
    @Bean
    @StepScope
    public MyBatisPagingItemReader<YourEntity> myBatisPagingItemReader(
            @Qualifier("batchSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        
        return new MyBatisPagingItemReaderBuilder<YourEntity>()
                .sqlSessionFactory(sqlSessionFactory)
                .queryId("com.example.mapper.YourMapper.selectWithPaging")
                .pageSize(1000)
                .build();
    }
}

 

MyBatisPagingItemReader작업 후, 모든 MyBatis 호출이 동일한 ExecutorType(SIMPLE)로 변환하여 해결