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

张开发
2026/4/17 11:42:27 15 分钟阅读

分享文章

SpringBoot 多数据源配置(读写分离基础)
随着项目变大单数据扛不住压力很常见的事这时候一般会先做读写分离主库、从库读减轻单库压力。而实现读写分离的第一就是先学会在 SringBoot 里配置多数据源。一、适用场景• 主库写入、从库读取读写分离基础版• 一个项目连接多个不同业务库• 微服务内部多库访问• 简单分库、不分表的场景二、整体思路1. 关闭 SpringBoot 默认数据源自动配置2. 手动构建两个或多个DataSource3. 为每个数据源配置独立的SqlSessionFactory、SqlSessionTemplate4. 按包或按注解切换数据源5. 事务注意多数据源下跨库事务需要额外处理三、引入依赖和单数据源 MyBatis 一致dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency四、application.yml 配置双数据源这里配置一个主库write、一个从库readspring: # 关闭自动配置数据源 autoconfigure: exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration # 主库写 datasource: master: url: jdbc:mysql://localhost:3306/testdb_master?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # 从库读 slave: url: jdbc:mysql://localhost:3306/testdb_slave?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # MyBatis 通用配置 mybatis: configuration: map-underscore-to-camel-case: true五、手动配置主数据源Master新建配置类DataSourceMasterConfigpackage 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新建配置类DataSourceSlaveConfigpackage 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); } }七、项目结构划分按包区分数据源com.demo ├── mapper │ ├── master # 主库写操作 │ │ └── UserMasterMapper.java │ └── slave # 从库读操作 │ └── UserSlaveMapper.java ├── service │ ├── MasterService │ └── SlaveService └── config ├── DataSourceMasterConfig.java └── DataSourceSlaveConfig.javaresources/mapper 下也要对应resources/mapper/master/*.xml resources/mapper/slave/*.xml这样不同包下的 Mapper 会自动走不同数据源实现写走主库、读走从库。八、Service 层使用示例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→ 启动报错2.Primary忘记加 → 找不到首选数据源3. Mapper 包路径、XML 路径写错 → 绑定失败4. 多个库表结构不一致 → 查询报错5. 误以为自动支持分布式事务 → 踩大坑十一、总结SpringBoot 多数据源核心就三步1. 关闭自动配置2. 手动注册多个 DataSource3. 按包/按注解区分 SqlSessionFactory掌握这一套你就理解了读写分离的底层原理再去用 Sharding-JDBC、dynamic-datasource 这类框架会非常轻松。

更多文章