vkolodrevskiy
vkolodrevskiy

Reputation: 599

Spring and Mybatis multiple data sources setup

My applications uses Spring3+MyBatis3. I'm trying to setup multiple data source for it. Setup looks like:

<!-- db1 setup-->
<bean id="db1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
    p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
    p:dataSource-ref="db1DataSource" />
<bean id="db1SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="db1SqlSessionFactory"/>
</bean>
<!-- db2 setup -->
<bean id="db2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
    p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
    p:dataSource-ref="db2DataSource" />
<bean id="db2SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="db2SqlSessionFactory"/>
</bean>

In the logs, I've found this message:

No unique bean of type [org.apache.ibatis.session.SqlSessionFactory] is defined: expected single matching bean but found 2: [db1SqlSessionFactory, db2SqlSessionFactory]

I googled and looked into mybatis manuals but couldn't find way how to setup multiple data sources with mybatis. Any ideas?

Upvotes: 4

Views: 23219

Answers (4)

Amir Shaikh
Amir Shaikh

Reputation: 207

To configure multiple data sources using Spring 3 and MyBatis 3

Make Following Changes In applicationContext.xml

Step 1: Configure the data source beans

<!-- DataSource 1 -->
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/db1" />
    <property name="username" value="username1" />
    <property name="password" value="password1" />
</bean>

<!-- DataSource 2 -->
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/db2" />
    <property name="username" value="username2" />
    <property name="password" value="password2" />
</bean>

Step 2: Configure the SqlSessionFactory beans

<!-- SqlSessionFactory for DataSource 1 -->
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource1" />
    <property name="mapperLocations" value="classpath:mappers1/*.xml" />
</bean>

<!-- SqlSessionFactory for DataSource 2 -->
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource2" />
    <property name="mapperLocations" value="classpath:mappers2/*.xml" />
</bean>

Step 3: Configure the MapperScannerConfigurer beans

<!-- MapperScannerConfigurer for DataSource 1 -->
<bean id="mapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper1" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1" />
</bean>

<!-- MapperScannerConfigurer for DataSource 2 -->
<bean id="mapperScannerConfigurer2" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper2" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2" />
</bean>

Step 4: Now You can configured above things in your code as per requirements

@Component
public class MyComponent {

    private SqlSessionFactory sqlSessionFactory;
    private MyMapper myMapper;

    @Autowired
    public MyComponent(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory,
                       @Qualifier("myMapper1") MyMapper myMapper) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.myMapper = myMapper;
    }

    // Use the sqlSessionFactory and myMapper in your component's methods
    // ...
}

Note:

Create separate mapper interfaces and XML files for each data source, corresponding to the basePackage values used in step 3

Upvotes: 0

Shuster
Shuster

Reputation: 1

In a DAO implementation use SqlSessionTemplate instead of SqlSessionDaoSupport. Inject bean db1SqlSessionTemplate or db2SqlSessionTemplate.

@Repository
public class TestDaoImpl implements TestDao{
    @Autowired
    private SqlSession db1SqlSessionTemplate;
    ...
    db1SqlSessionTemplate.selectList("testSelect");
    ...
}

When extending SqlSessionDaoSupport the context Spring does not know that you use SqlSession.

Upvotes: 0

user2144996
user2144996

Reputation: 41

also solved ! just reference your factory bean in MapperScannerConfigurer : sqlSessionFactoryBeanName

First data source >>>>>>>

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

<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource1"/>
</bean>

<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.package.p1"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
    </bean>

Second data source >>>>>>

<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource2"/>
    </bean>
<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.package.p2"/>
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"/>
</bean>

Upvotes: 4

vkolodrevskiy
vkolodrevskiy

Reputation: 599

solved, the problem was that I must specify directly reference to sqlSessionFactory

<bean id="myDao" class="org.mybatis.spring.mapper.MapperFactoryBean"
    p:sqlSessionTemplate-ref="db1SqlSessionTemplate"
    p:mapperInterface="my.project.domain.dao.MyDao"
    p:sqlSessionFactory-ref="db1SqlSessionFactory"/>

Upvotes: 2

Related Questions