SpringBoot 多数据源配置(读写分离基础)

随着项目变大,单数据扛不住压力很常见的事,这时候一般会先做读写分离 :主库、从库读,减轻单库压力。而实现读写分离的第一,就是先学会在 SringBoot 里配置多数据源


一、适用场景

  • • 主库写入、从库读取(读写分离基础版)

  • • 一个项目连接多个不同业务库

  • • 微服务内部多库访问

  • • 简单分库、不分表的场景

二、整体思路

    1. 关闭 SpringBoot 默认数据源自动配置
    1. 手动构建两个(或多个)DataSource
    1. 为每个数据源配置独立的 SqlSessionFactorySqlSessionTemplate
    1. 按包或按注解切换数据源
    1. 事务注意:多数据源下跨库事务需要额外处理

三、引入依赖

和单数据源 MyBatis 一致:

go 复制代码
<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>2.3.2</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

四、application.yml 配置双数据源

这里配置一个主库(write)、一个从库(read):

go 复制代码
spring:
  # 关闭自动配置数据源
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

# 主库(写)
datasource:
  master:
    url: jdbc:mysql://localhost:3306/testdb_master?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

  # 从库(读)
  slave:
    url: jdbc:mysql://localhost:3306/testdb_slave?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

# MyBatis 通用配置
mybatis:
  configuration:
    map-underscore-to-camel-case: true

五、手动配置主数据源(Master)

新建配置类:DataSourceMasterConfig

go 复制代码
package com.demo.config;

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.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
// 主库 Mapper 接口包路径
@MapperScan(basePackages = "com.demo.mapper.master",
            sqlSessionTemplateRef = "masterSqlSessionTemplate")
public class DataSourceMasterConfig {

    @Bean
    @ConfigurationProperties(prefix = "datasource.master")
    @Primary   // 标记为主数据源
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(
            @Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // XML 路径
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/master/*.xml"));
        return bean.getObject();
    }

    @Bean
    @Primary
    public SqlSessionTemplate masterSqlSessionTemplate(
            @Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

六、手动配置从数据源(Slave)

新建配置类:DataSourceSlaveConfig

go 复制代码
package com.demo.config;

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.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
// 从库 Mapper 接口包路径
@MapperScan(basePackages = "com.demo.mapper.slave",
            sqlSessionTemplateRef = "slaveSqlSessionTemplate")
public class DataSourceSlaveConfig {

    @Bean
    @ConfigurationProperties(prefix = "datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory slaveSqlSessionFactory(
            @Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/slave/*.xml"));
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate slaveSqlSessionTemplate(
            @Qualifier("slaveSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionTemplate);
    }
}

七、项目结构划分(按包区分数据源)

go 复制代码
com.demo
├── mapper
│   ├── master        # 主库:写操作
│   │   └── UserMasterMapper.java
│   └── slave         # 从库:读操作
│       └── UserSlaveMapper.java
├── service
│   ├── MasterService
│   └── SlaveService
└── config
    ├── DataSourceMasterConfig.java
    └── DataSourceSlaveConfig.java

resources/mapper 下也要对应:

go 复制代码
resources/mapper/master/*.xml
resources/mapper/slave/*.xml

这样不同包下的 Mapper 会自动走不同数据源,实现写走主库、读走从库


八、Service 层使用示例

go 复制代码
@Service
public class UserService {

    @Autowired
    private UserMasterMapper userMasterMapper;  // 主库:写

    @Autowired
    private UserSlaveMapper userSlaveMapper;    // 从库:读

    // 写操作:主库
    @Transactional
    public int addUser(User user) {
        return userMasterMapper.insert(user);
    }

    // 读操作:从库
    public User getUserById(Long id) {
        return userSlaveMapper.selectById(id);
    }
}

九、多数据源事务说明

  • • 单个数据源内事务正常使用 @Transactional

  • 跨多个数据源的事务不保证原子性

  • • 真正生产级读写分离一般用:

    • • Sharding-JDBC

    • • MyCat

    • • dynamic-datasource-spring-boot-starter

本文这种手动配置方式,适合学习原理、简单多库场景,真正高可用建议用成熟组件。


十、注意事项

    1. 没关闭 DataSourceAutoConfiguration → 启动报错
    1. @Primary 忘记加 → 找不到首选数据源
    1. Mapper 包路径、XML 路径写错 → 绑定失败
    1. 多个库表结构不一致 → 查询报错
    1. 误以为自动支持分布式事务 → 踩大坑

十一、总结

SpringBoot 多数据源核心就三步:

    1. 关闭自动配置
    1. 手动注册多个 DataSource
    1. 按包/按注解区分 SqlSessionFactory

掌握这一套,你就理解了读写分离的底层原理,再去用 Sharding-JDBC、dynamic-datasource 这类框架会非常轻松。

相关推荐
Java成神之路-1 小时前
Spring Cloud 微服务契约先行:为什么 Controller 建议要实现 Feign 接口?
spring·spring cloud·微服务
数智化管理手记2 小时前
海量数据如何沉淀有效数据资产?数据标准化治理方案如何搭建?
java·大数据·人工智能
cfm_29142 小时前
SpringAI + Ollama 本地大模型
java·开发语言·人工智能·语言模型
鲸采云SRM采购管理系统3 小时前
采购管理系统哪家好?2026最新测评对比
java·服务器·数据库
IT_陈寒3 小时前
Python的GIL让我多写了500行代码
前端·人工智能·后端
0x534 小时前
Java网络编程(二)
java·服务器·网络
Flittly4 小时前
【雕虫大技】Agent 动态 Skill 供应链安全加固(三):输出校验与治理闭环实战
java·spring boot·spring
Poo_Chai4 小时前
QT emit信号后完整处理流程,包括槽函数响应流程
java·开发语言·数据库
IT爱学堂4 小时前
精讲软件设计师(软考中级)一站式通关课_实战课程_慕课网
后端
瑞码空间4 小时前
Java 图形界面(GUI)完整知识点手册
java·开发语言·图形界面·swing