1.背景说明      2.配置多数据源步骤
         2.1 项目结构变更
         2.2 添加配置类
         2.3 修改配置文件数据连接配置信息
         2.4 多数据源配置导致@Transactional失效问题

1.背景说明

     一般一个项目中只会连接一个数据库.但是随着需求变更,会要求同一个项目中连接多个数据库,本文就讲一下如何在一个项目中对多个数据库进行连接.本文基于springboot+mybatis介绍如何进行多数据源连接(本文演示配置两个数据库,配置多个同理).

2.配置多数据源步骤

2.1 项目结构变更

     以连接不同的数据库进行分包,db1表示连接数据库database1,db2表示连接database2.项目结构如下:

springboot连接mysql mybatis springboot mybatis连接多个数据库_sql

2.2添加配置类

/**
 * @ClassName: MultiDataSourceConfig
 * @Desc: 多数据源配置
 * @Author: txm
 * @Date: 2022/12/11 9:59
 **/
@Configuration
public class MultiDataSourceConfig {

	// 创建自定义数据源db1
    @Bean(name = "db1")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource businessDbDataSource() {
        return DataSourceBuilder.create().build();
    }

	// 创建自定义数据源db2
    @Bean(name = "db2")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource newhomeDbDataSource() {
        return DataSourceBuilder.create().build();
    }
}

Db1Config配置类:

@Configuration
// 此处添加项目自定义mapper包路径,支持数组形式,指定SqlSessionFactory ,演示包路径已做修改
@MapperScan(basePackages = {"com.api.db1.order.mapper",
        "com.api.db1.pay.mapper",
        "com.api.db1.user.mapper",
        "com.api.db1.distribution.mapper",
        "com.api.db1.aliyun.mapper" }, sqlSessionFactoryRef = "sqlSessionFactoryDb1")
public class Db1Config {

    @Autowired
    @Qualifier("db1")
    private DataSource dataSourceDb1;


    @Bean
    public SqlSessionFactory sqlSessionFactoryDb1() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSourceDb1);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db1/**/*.xml"));
        // 自定义MyBatis configuration.配置打印和大小写转换
        org.apache.ibatis.session.Configuration personalConfiguration = new org.apache.ibatis.session.Configuration();
        personalConfiguration.setMapUnderscoreToCamelCase(true);
        personalConfiguration.setLogImpl(StdOutImpl.class);
        factoryBean.setConfiguration(personalConfiguration);
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateDb1() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryDb1());
    }
 /**
     * @Author: txm
     * @Description: 配置事务管理器
     * @Param: [dataSource]
     * @return: org.springframework.jdbc.datasource.DataSourceTransactionManager
     * @Date:  2023/1/31 14:00
     **/
    @Bean(name="db1TransactionManager")
    public DataSourceTransactionManager postgreTransactionManagerGenerate(){
        return new DataSourceTransactionManager(dataSourceDb1);
    }

}

Db2Config配置类:

@Configuration
// 此处添加项目自定义mapper包路径,支持数组形式,指定SqlSessionFactory ,演示包路径已做修改
@MapperScan(basePackages = {"com.api.db2.activityUser.mapper",
"com.api.db2.vote.mapper"}, sqlSessionFactoryRef = "sqlSessionFactoryDb2")
public class Db2Config {
    @Autowired
    @Qualifier("db2")
    private DataSource dataSourceDb2;


    @Bean
    public SqlSessionFactory sqlSessionFactoryDb2() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSourceDb2);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db2/**/*.xml"));
        // 自定义MyBatis configuration.配置打印和大小写转换
        org.apache.ibatis.session.Configuration personalConfiguration = new org.apache.ibatis.session.Configuration();
        personalConfiguration.setMapUnderscoreToCamelCase(true);
        personalConfiguration.setLogImpl(StdOutImpl.class);
        factoryBean.setConfiguration(personalConfiguration);
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateDb2() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryDb2());
    }
/**
     * @Author: txm
     * @Description: 配置事务管理器
     * @Param: [dataSource]
     * @return: org.springframework.jdbc.datasource.DataSourceTransactionManager
     * @Date:  2023/1/31 14:00
     **/
    @Bean(name="db2TransactionManager")
    public DataSourceTransactionManager postgreTransactionManagerGenerate(){
        return new DataSourceTransactionManager(dataSourceDb2);
    }

}

    说明
    自定义配置类Db1ConfigDb2Config中指定 @MapperScan之后可以将启动类上面的@MapperScan注解进行注释,@MapperScan的作用就是扫描mapper所在的包路径:

// modify by txm 2022/12/12 多数据源改造,包扫描添加到自定义数据源配置类Db1Config、Db2Config中
//@MapperScan("com.**.mapper")
@SpringBootApplication
public class H5Application {
    public static void main(String[] args) {
        SpringApplication.run(H5Application.class, args);
    }
}

    配置类中指定mapper配置文件所在路径,否则会提示:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found),添加内容如下::

factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db2/**/*.xml"));

    对应的配置文件是(可以进行注释):

mybatis:
     # 配置数据库映射文件 **表示是任意多级目录,适配dao/goods
    mapper-locations: classpath:/mapper/**/**/*.xml

    配置mybatis的日志打印与大小写转换:

// 自定义MyBatis configuration.配置打印和大小写转换
        org.apache.ibatis.session.Configuration personalConfiguration = new org.apache.ibatis.session.Configuration();
        personalConfiguration.setMapUnderscoreToCamelCase(true);
        personalConfiguration.setLogImpl(StdOutImpl.class);
        factoryBean.setConfiguration(personalConfiguration);

    添加之后配置文件中可以将以下内容进行注释:

mybatis:
     # 配置数据库映射文件 **表示是任意多级目录,适配dao/goods
    mapper-locations: classpath:/mapper/**/**/*.xml
     #spring boot集成mybatis的方式打印sql
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
     #spring boot记成mybatis将数据库字段字段转换华成驼峰形式
        map-underscore-to-camel-case: true

2.3 修改配置文件数据连接配置信息

spring:
#数据库信息设置
  datasource:
    db1:   # database1服务器地址
      jdbc-url: jdbc:mysql://xxx.xxx.xx.xx:3308/database1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
      username: ****
      password: ****
      driver-class-name: com.mysql.cj.jdbc.Driver
    db2:  # database2服务器地址 
      jdbc-url: jdbc:mysql://xxx.xxx.xx.xx:3308/database2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
      username: ****
      password: ****
      driver-class-name: com.mysql.cj.jdbc.Driver
      # 配置数据库连接池
      type: com.zaxxer.hikari.HikariDataSource
      hikari:
        minimum-idle: 5  # 最小空闲连接数量
        idle-timeout: 180000 # 单位毫秒,此处设置3分钟,空闲连接存活最大时间,默认600000(10分钟)
        maximum-pool-size: 10 # 连接池最大连接数,默认是10
        auto-commit: true     # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
        pool-name: MyHikariCP  # 连接池名称
        max-lifetime: 1800000 # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
        connection-timeout: 30000  # 数据库连接超时时间,默认30秒,即30000

    注意:要将url替换成jdbc-url,否则会提示以下内容:

java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.

    关于数据库连接类型可以选用springboot默认支持的Hikari,性能会更好!如果对Hikari无配置要求,可以不用添加Hikari相关的配置信息.演示内容中配置了db2的Hikari信息.

2.4 多数据源配置导致@Transactional失效问题

    多数据源改造之后会导致@Transactional失效,处理方案如下:
Db1Config.javaDb2Config.java中需要进行注册对应的事务管理器,已经在刚开始的案例中进行了补充。使用的时候需要根据不同的数据源替换掉默认的事务管理器。
以抽奖接口为例说明:
原接口:

@Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized DrawVo  luckDraw(LuckDrawDto luckDrawDto) {
		// 忽略业务处理逻辑
}

多数据源事务管理改造之后:

@Override
    @Transactional(transactionManager = "db2TransactionManager",rollbackFor = Exception.class)
    public synchronized DrawVo  luckDraw(LuckDrawDto luckDrawDto) {
		// 忽略业务处理逻辑
}

    以上是关于springboot中配置多数据源的实战记录,希望对有同样需求的同学有所帮助,感觉有所收获欢迎点赞或是留言!