您好,欢迎访问数据库运维|优化|安装|迁移|服务官网!
13261661949
spring boot 配置多数据源-行业新闻-数据库运维|优化|安装|迁移|服务_uDBok.com

新闻动态

联系我们

spring boot 配置多数据源-行业新闻-数据库运维|优化|安装|迁移|服务_uDBok.com

地址:北京市昌平区高新经济开发区
手机:13261661949

咨询热线13261661949

spring boot 配置多数据源

发布时间:2026-10-12 15:30:00人气:1038

项目里突然要接第二个数据库,这事儿搁谁身上都得皱眉头。明明Spring Boot用得好好的,单数据源配置写起来跟喝水一样简单,结果一牵扯到多数据源,各种坑就冒出来了。连接池怎么分?事务归谁管?Mapper扫描会不会串?网上教程翻了一堆,要么只讲理论不给能跑的代码,要么给个demo就完事儿,真搬到生产环境立马露馅。今天不整虚的,直接把配置多数据源那点事儿掰开揉碎了说清楚,从依赖引入到动态切换,每一步都给你看实际代码。

spring boot 配置多数据源

先搞清楚一个核心问题:Spring Boot里数据源本质上是注册到容器里的Bean。单数据源的时候,自动配置帮你把DataSource、SqlSessionFactory、PlatformTransactionManager全绑好了,你只管写Mapper接口。但一旦数据源变成两个,自动配置就懵了——它不知道哪个是主哪个是次,干脆全都不配置,把主动权交还给你。这时候你得手动声明两个DataSource,并且明确告诉Spring:这个主,那个从。最简单的做法是在配置类里用@Primary注解标出一个主数据源,剩下的那个靠@Qualifier指定。

不过光有两个DataSource不够,MyBatis或者JPA还得知道怎么用它们。拿MyBatis举例,你得分别为每个数据源创建独立的SqlSessionFactory和Mapper扫描路径。假设你有主库的Mapper放在.master下,从库的放在.slave下,那么就得写两个@MapperScan,分别指定不同的SqlSessionFactoryRef。这时候有个特别容易踩的坑:如果你用了Spring Boot的自动配置,它默认会扫描@SpringBootApplication所在包下的所有Mapper接口,结果两个库的Mapper全被塞进同一个SqlSessionFactory里,运行起来直接报错说找不到某个表的映射。解决办法是排除掉MyBatis的自动配置类,在启动类上加一个exclude参数。

连接池这块也得单独拎出来说。很多人图省事,直接用Spring Boot默认的HikariCP,两个数据源共用一个配置。但生产环境里主库和从库的负载完全不一样,主库可能要承受高频写入,从库侧重读多写少,连接池大小、超时时间、最大等待数都应该分开调。比如主库maxPoolSize设为20,从库只给10,万一从库被慢查询拖垮,也不至于把主库的资源全占掉。另外别忘了给两个数据源设置不同的name,不然监控的时候根本分不清哪个是哪个。

接下来是事务管理。默认情况下,@Transactional注解用的是主数据源的事务管理器,你往从库写数据的时候,如果没指定事务管理器,它会直接走主库的事务,数据倒是写进去了,但从库的事务状态压根没被记录。正确做法是配置两个PlatformTransactionManager,一个叫masterTransactionManager,一个叫slaveTransactionManager,然后在Service层的方法上显式声明@Transactional("slaveTransactionManager")。但这里有个更深的坑:如果你在一个事务里先查主库再查从库,分布式事务的问题就冒出来了。Spring Boot单机环境下没法解决跨数据源的强一致性,要么用Atomikos这类分布式事务中间件,要么就得接受最终一致性,在业务层面做补偿。

说到动态切换数据源,这是另一个高频需求。比如同一个Service方法,根据用户请求的参数决定走哪个库,这时候静态配置就玩不转了。常见的做法是用AbstractRoutingDataSource,它内部维护一个目标数据源的Map,通过determineCurrentLookupKey()方法动态返回当前线程应该用哪个key。配合ThreadLocal存上下文,在进入Service前手动设置数据源标识,方法执行完再清理掉,就能实现读写分离或者按租户切换。但用这招必须注意线程池的问题——如果代码跑到@Async异步方法里,ThreadLocal的值不会自动传递,得额外用TransmittableThreadLocal或者手动传参。

还有个容易忽略的点是数据库连接初始化的顺序。Spring Boot启动时会自动执行schema.sql和data.sql,但这是针对主数据源的。如果你想让从库也初始化表结构,得手动配置DataSourceInitializer,并且确保它在两个数据源Bean创建之后再执行。另外一些框架比如Flyway,默认也是绑定主数据源的,要支持多数据源就得为每个数据源单独建Flyway配置,还得管理好迁移脚本的目录结构,建议按照数据库类型或者业务模块分文件夹存放。

说下监控和排查。多数据源环境下,慢SQL定位的难度直接翻倍。主库从库的日志混在一起,你根本看不出哪条SQL打到了哪个库上。建议在配置连接池的时候,为每个数据源设置独立的监控指标前缀,比如HikariCP的metricRegistry参数,配合Micrometer输出到Prometheus,这样在Grafana里能按数据源分别看活跃连接数、等待时间、执行次数。日志方面,给不同数据源的Mapper接口所在的包设置不同的日志级别,排查问题的时候只打开对应包的DEBUG日志,能省不少时间。

回到开头那个问题。Spring Boot配置多数据源,本质上是在跟框架的自动配置机制做斗争——你得手动接管那些原本被自动搞定的部分,同时还得保证两个数据源之间的隔离性。从最基础的DataSource配置,到SqlSessionFactory拆分,再到事务管理和动态路由,每一层都有对应的坑。但换个角度想,这恰恰是Spring Boot的设计哲学:约定优于配置,但约定可以被显式覆盖。只要摸清了它的套路,多数据源配置就是一个熟练工种的活儿。

用不用多数据源,其实得想清楚一个问题:你的业务真的需要吗?很多时候,读写分离用中间件比如ShardingSphere更省心,多租户场景用数据库本身的行级安全机制也能解决。Spring Boot的多数据源方案,胜在简单直接、可控性强,但也意味着所有的麻烦都得自己扛。一旦决定了用它,就得接受它的全部——包括那些让你抓狂的坑。

推荐资讯

13261661949