MyBatis cannot change the ExecutorType when there is an existing transaction 오류

스프링 배치 잡을 실행할 때 MyBatis 쿼리 실행 부분에서 다음과 같은 오류가 발생하는 경우가 있었다.

cannot change the ExecutorType when there is an existing transaction

이 에러는 존재하는 트랜잭션이 있을 경우 MyBatis의 ExecutorType (SIMPLE, BATCH, REUSE) 을 변경할 수 없다는 의미이다.

원인

스프링 배치 잡에서만 날 수 있는 오류는 아니고 MyBatis를 사용하고 트랜잭션 설정된 부분이 있다면 발생할 수 있을 것이다.

트랜잭션으로 묶여있는 범위 내에서는 배치 잡 내에서 동일 데이터 소스에 대해서는 동일 SqlSessionTemplate을 사용하게 될 것인데,
ExecutorTypeSqlSessionTemplate에 종속적인 설정 값이다.

그러다보니 ExecutorType이 다른 동일 데이터 소스를 사용해도 트랜잭션 때문에 이전 ExecutorTypeSqlSessionTemplate이 사용되기 때문에 위 오류가 발생한다.


해결 방법

해결하는 방법은 상황에 따라 다르겠지만 만약 동일 ExecutorType을 사용하도록 맞추려고 한다면,
다른 ExecutorType을 사용한 DAO에 동일한 ExecutorType을 가진 SqlSessionTemplate을 사용하도록 설정하면 된다.

예를 들어서, BATCH 타입으로 트랜잭션이 수행되다가 SIMPLE 타입을 사용하는 DAO 메소드 하나가 실행되어 에러가 발생했다면,
그 DAO에 다음과 같이 설정해주면 된다.

<bean id="personDAO" class="com.sheerheart.dao.PersonDAO">
 <property name="sqlSessionTemplate" ref="sqlSessionTemplate-batch" /> 
</bean>

<bean id="sqlSessionTemplate-batch" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
 <constructor-arg index="0" ref="sqlSessionFactory"/>
 <constructor-arg index="1" value="BATCH"/>
</bean>

만약 MapperScan을 사용하고 있어서 DAO 인터페이스만 존재하는 상황이라면 다음과 같이 하면 된다.

<bean id="personDAO" class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="mapperInterface" value="com.sheerheart.dao.PersonDAO"/>
 <property name="sqlSessionTemplate" ref="sqlSessionTemplate-batch"/>
</bean>

<bean id="sqlSessionTemplate-batch" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
 <constructor-arg index="0" ref="sqlSessionFactory"/>
 <constructor-arg index="1" value="BATCH"/>
</bean>

만약 같은 트랜잭션에 묶이지 않아도 되는 것이라면 트랜잭션에 묶이지 않도록 제외 처리하는 등의 방법이 있다.