1. 项目概述
在当今企业级应用开发中,多数据源支持已成为标配需求。无论是读写分离、分库分表,还是对接不同业务系统的数据库,都需要我们掌握多数据源配置的核心技术。最近我在一个金融项目中实践了SpringBoot3.x + MybatisPlus + Druid的多数据源方案,并完整实现了Druid监控统计功能,过程中踩了不少坑也积累了些实战经验,今天就来系统梳理下这套技术栈的配置要点。
这套组合拳的优势很明显:SpringBoot3.x提供了现代化的开发体验,MybatisPlus极大简化了数据库操作,而Druid作为阿里开源的数据库连接池,不仅性能优异,其内置的监控功能更是排查SQL性能问题的利器。但在实际配置时,三者的版本兼容性、多数据源的线程隔离、监控页面的安全防护等问题都需要特别注意。
2. 环境准备与基础配置
2.1 依赖管理
首先确保你的项目是基于SpringBoot3.x构建的。在pom.xml中需要引入以下核心依赖:
<dependencies> <!-- SpringBoot Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MybatisPlus Starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- Druid Starter --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-3-starter</artifactId> <version>1.2.18</version> </dependency> <!-- 数据库驱动 (以MySQL为例) --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> </dependencies>特别注意:SpringBoot3.x必须使用druid-spring-boot-3-starter,传统starter不兼容。这是很多开发者容易踩的第一个坑。
2.2 基础配置
在application.yml中配置主数据源(这里以MySQL为例):
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/main_db?useSSL=false&serverTimezone=UTC username: root password: 123456 druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 600003. 多数据源配置实现
3.1 数据源配置类
我们需要为每个数据源创建独立的配置类。以下是主从两个数据源的典型配置:
@Configuration @MapperScan(basePackages = "com.example.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate") public class PrimaryDataSourceConfig { @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "primarySqlSessionFactory") public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath:mapper/primary/*.xml")); return factory.getObject(); } @Bean(name = "primaryTransactionManager") public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "primarySqlSessionTemplate") public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }从数据源配置类似,只需更换bean名称和路径前缀。完整的配置应该包含:
- 数据源bean
- SqlSessionFactory
- 事务管理器
- SqlSessionTemplate
3.2 动态数据源路由
对于需要动态切换数据源的场景,我们可以实现AbstractRoutingDataSource:
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } } public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } }使用时通过AOP或手动调用切换:
DataSourceContextHolder.setDataSourceType("secondary"); // 执行数据库操作 DataSourceContextHolder.clearDataSourceType();4. Druid监控配置与安全防护
4.1 监控中心配置
在application.yml中启用Druid监控:
spring: datasource: druid: stat-view-servlet: enabled: true url-pattern: /druid/* login-username: admin login-password: druid123 reset-enable: false web-stat-filter: enabled: true url-pattern: /* exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" filter: stat: enabled: true log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: enabled: true config: drop-table-allow: false4.2 安全防护要点
Druid监控页面如果暴露在外网非常危险,必须做好防护:
- 强制修改默认账号密码
- 添加IP白名单限制(通过配置stat-view-servlet.allow)
- 生产环境建议通过内网访问或添加额外认证层
- 定期检查Druid版本,及时修复安全漏洞
重要提示:我曾遇到过因Druid监控页面未授权访问导致数据库信息泄露的事故。建议在安全要求高的场景下,通过Spring Security添加额外保护。
5. 常见问题与解决方案
5.1 连接池耗尽问题
症状:系统运行一段时间后出现"获取连接超时"异常。
解决方案:
- 检查连接泄漏:在Druid配置中添加:
spring: datasource: druid: remove-abandoned: true remove-abandoned-timeout: 300 log-abandoned: true- 合理设置连接池参数(根据实际负载调整)
- 确保每次操作后关闭Connection/Statement/ResultSet
5.2 多数据源事务问题
跨数据源的事务需要引入分布式事务解决方案(如Seata)。对于单数据源事务,确保:
- 在Service方法上添加@Transactional注解
- 指定正确的事务管理器:
@Transactional(transactionManager = "primaryTransactionManager") public void businessMethod() { // ... }5.3 MybatisPlus分页失效
在多数据源环境下,分页插件需要单独配置:
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }6. 性能优化建议
连接池参数调优:
- initialSize: 初始连接数(建议5-10)
- minIdle: 最小空闲连接(建议与initialSize相同)
- maxActive: 最大连接数(根据并发量设置,通常20-100)
- maxWait: 获取连接超时时间(建议1000-3000ms)
SQL监控:
- 开启慢SQL记录(slow-sql-millis)
- 定期分析Druid监控中的SQL执行统计
多数据源负载均衡:
- 对于读多写少的场景,可以考虑使用读写分离
- 使用@DS注解动态切换数据源(需集成dynamic-datasource组件)
这套配置方案在我们生产环境已经稳定运行半年多,支撑了日均百万级的数据库操作。关键在于:
- 合理的连接池参数
- 严格的监控告警
- 定期的性能分析
- 安全防护措施到位
最后分享一个实用技巧:在开发环境可以开启Druid的SQL防火墙功能,它能有效拦截危险SQL(如全表删除),避免开发人员误操作导致数据丢失。配置如下:
spring: datasource: druid: filter: wall: enabled: true config: delete-allow: false drop-table-allow: false