Spring-Mybatis와 Spring 개발환경에서 여러 DB (multiple DB)를 동시에 사용할 때, ibatis처럼 쓰면 문제가 생길 수 있다. 즉 DB가 꼬이거나 SqlSession instance로 인한 문제가 발생할 수 있다. 

(에러 내용)  No unique bean of type [org.apache.ibatis.session.SqlSessionFactory] is defined

(결론) org.mybatis.spring.mapper.MapperScannerConfigurer 클래스 대신 org.mybatis.spring.mapper.MapperFactoryBean을 사용해서야 문제가 해결됨

 



다음과 같은 기본적인 설정을 쓰고 있었다.

 

    <bean id="batch1SqlSession" class="org.mybatis.spring.SqlSessionTemplate" >
          <constructor-arg index="0" ref="batch1SqlSessionFactory" />
    </bean>

        <bean id="batch2SqlSession" class="org.mybatis.spring.SqlSessionTemplate" >
          <constructor-arg index="0" ref="batch2SqlSessionFactory" />
    </bean>

 

 

 

<bean id="xxxxMapper"  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <property name="basePackage" value="xxxx" />
       <property name="sqlSessionFactoryBeanName" value="batch1SqlSessionFactory" />
   </bean>

 

 

한 개의 DB 사용시는 문제 없는데, 여러 개의 DB 접속시에 문제가 발생할 수 있다. 

(원인은 잘못된 API 사용이다.)

 

 

즉, org.mybatis.spring.mapper.MapperScannerConfigurer를 사용하는 경우

1) basePackage를 잘못 지정해서 No MyBatis mapper was found in 'xxxx' package. 가 발생한다.

(MapperScannerConfigurer.java:397) No MyBatis mapper was found in 'xxxx' package. Please check your configuration.

 

2) Exception 발생

 

class A1 {

    @Autowired
     SqlSession batch1SqlSession;
}

 

class A2 {

    @Autowired
    SqlSession batch2SqlSession;
}

 

SqlSession을 이용하려다가 No unique bean of type 이라는 exception을 만날 수 있다.

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.mybatis.spring.SqlSessionTemplate] is defined: expected single matching bean but found 2: [batch1SqlSession, batch2SqlSession]

  구글 검색하면, Qualifier Annotation 같은 것으로 해결할 수 있다고 하나, 잘못된 API 사용이기 때문에 해결할 수 있다.

 

3) 엉뚱한 DB로 접근한다.

설정을 어떻게 어떻게 바꿨는데..

A db, B db에 접속했는데, A db에 ‘가’ 쿼리가 날아가기를 기대했는데, B db에 ‘나’쿼리가 접속하여 테이블 없다는 Exception이 발생할 수 있다.

 

4) 이런 문제를 해결하기 위해서 약간의 공수를 사용해서 문제를 해결할 수 있다.

  1)번 예제의 xxxxMapper bean id의 basePackage를 엉뚱한데 두면 해결이 된다.

   다만 WARN 에러로그가 남겨진다.

[WARN] No MyBatis mapper was found in ‘XXXX’ package. Please check your configuration.

 

소스상 보면, 요행으로 문제가 되는 코드를 피해갈 뿐이었다.

 

http://jarvana.com/jarvana/view/org/mybatis/mybatis-spring/1.0.2/mybatis-spring-1.0.2-sources.jar!/org/mybatis/spring/mapper/MapperScannerConfigurer.java?format=ok

 

@Override protected Set<BeanDefinitionHolder> doScan(String... basePackages) {

Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

if (beanDefinitions.isEmpty()) {

logger.warn("No MyBatis mapper was found in '" + MapperScannerConfigurer.this.basePackage + "' package. Please check your configuration.");

} else {

}

 

 

=> 해결

Spring-Mybatis 문서를 참조 (http://code.google.com/p/mybatis/wiki/Spring)해서  다시 코딩하기로 했다. 

org.mybatis.spring.mapper.MapperScannerConfigurer 클래스 대신 org.mybatis.spring.mapper.MapperFactoryBean을 사용해서야 문제가 해결되었다.

 

1) bean 설정

 

 

<bean id="googleGatewayDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
….
    </bean>
  

 

    <bean id="googleGatewaySqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="googleGatewayDataSource" />
        <property name="configLocation" value="classpath:storage/google-gateway-service-config.xml" />
    </bean>
   
        <bean id="gatewaySqlSession" class="org.mybatis.spring.SqlSessionTemplate" >
          <constructor-arg index="0" ref="googleGatewaySqlSessionFactory" />
    </bean>

 

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
     <property name="mapperInterface" value=" com.google.center.repository.GoolgeGatewayDAO" />

     <property name="sqlSessionFactory" ref="googleGatewaySqlSessionFactory" />
     <property name="sqlSessionTemplate" ref="googleGatewaySqlSession" />
</bean>     

 

2) 소스 : mybatis mapper 설정과 연동하는 DAO 코드

 

public interface GoolgeGatewayDAO {

     public Template getTemplate(@Param("channelId") String channelId, @Param("language") String language);

     public String getI18nChannelName(@Param("channelId") String channelId, @Param("language") String language);

}



또는 간결하게 아래 stackoverflow를 통해 쉽게 해결가능하다. 

http://stackoverflow.com/questions/4746766/spring-and-mybatis-multiple-data-sources-setup


Posted by '김용환'
,