Configuring Multiple Data Sources with MyBatis and Druid in Spring Boot

Database Setup

This example demonstrates a read-write database separation setup. The write database (mybatis1) handles write operations, while the read database (mybatis) handles read operations. Both databases share identical table structures.

Write Database Schema

CREATE DATABASE `mybatis1` DEFAULT CHARACTER SET utf8;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Read Database Schema

CREATE DATABASE `mybatis` DEFAULT CHARACTER SET utf8;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Dependencies Configuration

Include the following dependencies in your Maven configuration:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.11</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
</dependencies>

Data Access Layer Configuration

Read Data Mapper

package com.example.read.mapper;

import com.example.model.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface ReadUserMapper {
    @Select("SELECT * FROM user")
    List<User> findAll();

    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(int id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    void save(User user);

    @Update("UPDATE user SET name=#{name}, age=#{age} WHERE id =#{id}")
    void modify(User user);

    @Delete("DELETE FROM user WHERE id =#{id}")
    void remove(int id);
}

Write Data Mapper

package com.example.write.mapper;

import com.example.model.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface WriteUserMapper {
    @Select("SELECT * FROM user")
    List<User> findAll();

    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(int id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    void save(User user);

    @Update("UPDATE user SET name=#{name}, age=#{age} WHERE id =#{id}")
    void modify(User user);

    @Delete("DELETE FROM user WHERE id =#{id}")
    void remove(int id);
}

Data Source Configuration Classes

Write Data Source Configuration

package com.example.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.example.write.mapper", 
           sqlSessionTemplateRef = "writeSqlSessionTemplate")
public class WriteDataSourceConfig {

    @Bean(name = "writeDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.write")
    @Qualifier("writeDataSource")
    @Primary
    public DataSource writeDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "writeSqlSessionFactory")
    @Primary
    public SqlSessionFactory writeSqlSessionFactory(
            @Qualifier("writeDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }

    @Bean(name = "writeTransactionManager")
    @Primary
    public DataSourceTransactionManager writeTransactionManager(
            @Qualifier("writeDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "writeSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate writeSqlSessionTemplate(
            @Qualifier("writeSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

Read Data Source Configuration

package com.example.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.example.read.mapper", 
           sqlSessionTemplateRef = "readSqlSessionTemplate")
public class ReadDataSourceConfig {

    @Bean(name = "readDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.read")
    @Qualifier("readDataSource")
    public DataSource readDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "readSqlSessionFactory")
    public SqlSessionFactory readSqlSessionFactory(
            @Qualifier("readDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }

    @Bean(name = "readTransactionManager")
    public DataSourceTransactionManager readTransactionManager(
            @Qualifier("readDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "readSqlSessionTemplate")
    public SqlSessionTemplate readSqlSessionTemplate(
            @Qualifier("readSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

Application Properties Configuration

# Read Data Source Configuration
spring.datasource.druid.read.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.druid.read.username=root
spring.datasource.druid.read.password=123456
spring.datasource.druid.read.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.read.type=com.alibaba.druid.pool.DruidDataSource

# Write Data Source Configuration
spring.datasource.druid.write.url=jdbc:mysql://localhost:3306/mybatis1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.druid.write.username=root
spring.datasource.druid.write.password=123456
spring.datasource.druid.write.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.write.type=com.alibaba.druid.pool.DruidDataSource

# MyBatis Configuration
mybatis.type-aliases-package=com.example.model

Controller Implementation

package com.example.controller;

import com.example.model.User;
import com.example.read.mapper.ReadUserMapper;
import com.example.write.mapper.WriteUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
@RequestMapping("/users")
public class UserController {

    @Autowired
    private WriteUserMapper writeMapper;

    @Autowired
    private ReadUserMapper readMapper;

    @GetMapping
    public String getAllUsers(Model model) {
        List<User> users = readMapper.findAll();
        model.addAttribute("users", users);
        return "user-list";
    }

    @PostMapping
    public String createUser(Model model) {
        User newUser = new User();
        newUser.setName("testuser");
        newUser.setAge(25);
        writeMapper.save(newUser);
        
        List<User> users = writeMapper.findAll();
        model.addAttribute("users", users);
        return "user-list";
    }
}

Application Configuration

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = {"com.example.config", "com.example.controller"})
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Testing the Configuration

To verify the setup:

  • Acess http://localhost:8080/users to retrieve data from the read database
  • Submit a POST request to create new records in the write database
  • Verify that read operations use the read database and write operations use the write database
  • Check Druid monitoring interface for both data source connections

Tags: SpringBoot MyBatis druid MultipleDataSources DatabaseConfiguration

Posted on Tue, 25 Aug 2026 16:15:35 +0000 by roswell