本文分享自华为云社区 《实战指南,SpringBoot + Mybatis 如何对接多数据源》,作者:战斧。
在我们开发一些具有综合功能的项目时,往往会碰到一种情况,需要同时连接多个数据库,这个时候就需要用到多数据源的设计。而Spring与Myabtis其实做了多数据源的适配,只需少许改动即可对接多数据源。本期我们就贴近实战,以一个单数据源的Demo为例,讲述将其改为多数据源项目的过程,希望大家能有所体会。
因为SpringBoot对数据源有着高度的默认配置,只配置一个数据源时,该数据源会被作为默认,所以对接单数据源其实是非常简单的。如果你的工程采用的yaml格式配置文件,我们仅需做如下配置:
spring: #数据库连接配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springtest username: root password: root
如果是采用properties配置文件的也是一样的:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springtest spring.datasource.username=root spring.datasource.password=root
我们以曾经搭建的工程为原始模板,进行对接多数据源的操作。没看过的可以点此查看: 从零开始,手把手教你搭建Spring Boot后台工程并说明
因为仅变动数据源,所以我们不改动其他层级,仅仅将 mapper 拆为 mapper1 与 mapper2 两部分
然后我们需要在 application.properties 或者 application.yml 中定义多个数据源:
spring: #数据库连接配置 datasource1: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/springtest2 username: root password: root datasource2: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://127.0.0.1:3306/springtest username: root password: root
这里有两个细节需要注意:
datasource1
和 datasource2
。而不再保留datasource
,这样SpringBoot就不再会为我们设定默认数据库Hikari
,该连接池数据源的地址字段为jdbc-url
而非 url
。在只有单个数据源时,SpringBoot走默认数据源逻辑为我们把 url
与 jdbc-url
进行映射,保证我们获得数据源。此时我们自己设置的数据源没有进行映射处理,就需要保证字段符合Hikari
的要求。否则会出现 java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName
异常仅有配置文件可不行,接下来,我们需要在代码中读取到配置,并建立两个数据源。如下,每个数据源都有隔离的mapper接口、xml文件、会话工厂及会话模板
第一个数据源 如下(示例):
@Configuration @MapperScan(basePackages = "com.zhanfu.springboot.demo.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1") public class DataSource1Config { @Bean @ConfigurationProperties(prefix = "spring.datasource1") public DataSource dataSource1() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory sqlSessionFactory1() throws Exception { SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource1()); String locationPattern = "classpath*:/mapper1/*.xml"; PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern)); return sessionFactoryBean.getObject(); } @Bean(name = "sqlSessionTemplate1") public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
配置第二个数据源 DataSource2Config
@Configuration @MapperScan(basePackages = "com.zhanfu.springboot.demo.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2") public class DataSource2Config { @Bean @ConfigurationProperties(prefix = "spring.datasource2") public DataSource dataSource2() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory sqlSessionFactory2() throws Exception { SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource2()); String locationPattern = "classpath*:/mapper2/*.xml"; PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern)); return sessionFactoryBean.getObject(); } @Bean(name = "sqlSessionTemplate2") public SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } @Bean(name = "productMapper") public ProductMapper mapper2(@Qualifier("sqlSessionTemplate2") SqlSessionTemplate sqlSessionTemplate) throws Exception { return sqlSessionTemplate.getMapper(ProductMapper.class); } }
为两个数据源分别配置自己的事务管理器,如果你的项目里通篇没有方法级别的事务(一个SQL就是一个事务),那不设置这个也不影响,否则还是建议加上。
@Configuration public class TransactionManagerConfig { @Autowired private DataSource dataSource1; @Autowired private DataSource dataSource2; @Bean public PlatformTransactionManager txManager1() { return new DataSourceTransactionManager(dataSource1); } @Bean public PlatformTransactionManager txManager2() { return new DataSourceTransactionManager(dataSource2); } }
我们把两张表拆进两个库中,以两个库模拟两个数据源,使得程序可以同时连接两个库
浏览器输入 http://127.0.0.1:8080/user/findall 查询接口成功
再在浏览器输入 http://127.0.0.1:8080/product/findall 查询第二个库的数据亦成功返回
这样我们就完成了一个工程同时连接两个数据源。
经过上述的操作,我们已经成功把项目对接了多数据源。当然,方案肯定不止这一种,后续围绕该问题,我们还会讲解其他方式。但不论是什么方式,主旨都是加深大家对SpringBoot 和 Mybatis的理解,我们曾经梳理过全流程,但只是蜻蜓点水带大家看一遍大体轮廓,并不足以让你精通,后面本专栏将继续深入讲解。