SpringBoot配置多数据源

SpringBoot配置多数据源总结

1.为何配置多数据源?

首先,当一个系统需要集成多个项目的时候,配置多数据源是不可避免的,比如在一个系统中,需要有主从库的配置(主库负责增删改,从库负责查询),或者当你的系统/服务需要对接多个系统,存入多个不同的表的时候,就需要配置多数据源。

P.S 也可以在服务中调用RPC通信去调用别的服务的方法去调用多数据源,但是这样有以下几个弊端:

(1)不同服务会有不同的git分支,当大家合作开发时,分支不同,而你的代码要去别人的服务里做修改,这样会导致一些版本和代码的冲突,不方便。

(2)当你的业务需要这个数据源做主要支持的时候,使用RPC会导致你频繁的去调用其他人的服务和其他项目的数据库,而且当其他人对这个数据源进行改动后,会对你的业务影响很大,这样的设计并不合理。

当然具体业务也需要具体分析,因地制宜,当无法避免配置多数据源时,要在SpringBoot/SpringCloud工程中配置多数据源

2.配置多数据源的思路

配置多数据源其实有很多种不同的方法,但是这些方法都大同小异,我在这里提供一个在我们项目中比较常见的一种配置多数据源的思路。

(1)application.yml/application.properties中,加入相应数据源的url/driverClass/username/password等信息,这里要说明一下,不同项目使用不同的数据库连接池,在我的例子中,使用的是阿里的Druid连接池

(2)配置多数据源时,要排除此项目/服务中不需要配置单数据源,所以在启动类注解SpringBootApplication上,使用exclude排除掉DataSourceAutoConfiguration这个类,此处一定要注意,如果不排除掉,数据源配置会是访问单数据源从而导致失败。

(3)配置不同数据源的Config类,这里每个项目使用的数据源个数也都是不同的,这里我们的demo提供的是一个双数据源的配置,所以我们有两个数据源配置类,这里要强调一下,数据源要有主从区别,主数据源一定要添加@Primary注解。具体的需要注意的点都写在注释了,所有数据信息均为测试数据信息,不包含机密信息~

e.g:

application.properties

# 从库
druid.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb1?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
druid.datasource.username=root
druid.datasource.password=root

# 主库
druid.primarydb.url=jdbc:mysql://127.0.0.1:3306/testdb2?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
druid.primarydb.username=root
druid.primarydb.password=root

DataApplication.java

@PropertySource(value = "classpath:common-${spring.profiles.active}.properties", encoding = "UTF-8")
@RestController
@Log4j2
// 这个注解一定要加上
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DataApplication {

    public static void main(String[] args) {
        SpringApplication.run(DataApplication.class, args);
        try {
            System.setProperty("hostName", InetAddress.getLocalHost().getHostName());
            Environment environment = ApplicationContextHolder.getBean(Environment.class);
            String prefix = environment.getProperty("redis.key.prefix");
            log.info("当前redis前缀:{}", prefix);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

RecruitmentDataSourceConfig

// Configuration声明是代码中的配置相关信息
@Configuration
// 扫包
@MapperScan(basePackages =
        "com.recruitment.infrastructure.mapper.generate.recruitment",
        sqlSessionTemplateRef = "recruitmentSqlSessionTemplate")
public class RecruitmentDataSourceConfig {

    /**
     * 扫描application为druid.primarydb,生成Druid数据源
     * testdb2是主数据源,要使用@Primary注解
     * @return
     */
    @Bean
  	// 通过前缀去读相关数据库信息
    @ConfigurationProperties(prefix = "druid.primarydb")
    @Primary
    public DataSource recruitmentDataSource() {
        return new DruidDataSource();
    }

    /**
     * 配置SqlSessionFactory
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean
    @Primary
  	// 通过Qualifier注解,通过名称去加载对应的bean,这样在代码中不需要额外配置别的东西,直接注入所需要的mapper即可
    public SqlSessionFactory recruitmentSqlSessionFactory(
            @Qualifier("recruitmentDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setVfs(SpringBootVFS.class);
        // 配置configuration
        tk.mybatis.mapper.session.Configuration configuration = new tk.mybatis.mapper.session.Configuration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        // 会自动映射任意复杂的结果集(无论是否嵌套)
        configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);
        // 采用驼峰式命名方法
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(
                "classpath*:com/recruitment/infrastructure/mapper/config/recruitment/*.xml"));
        return bean.getObject();
    }

    /**
     * 配置事务
     * @param dataSource
     * @return
     */
    @Bean
    @Primary
    public DataSourceTransactionManager recruitmentTransactionManager(
            @Qualifier("recruitmentDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 配置sqlSessionFactory模板
     * @param sqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean
    @Primary
    public SqlSessionTemplate recruitmentSqlSessionTemplate(
            @Qualifier("recruitmentSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

同理 从库配置与上面类似

DemandDataSourceConfig.java

@Configuration
@MapperScan(basePackages =
        "com.recruitment.infrastructure.mapper.generate.demand",
        sqlSessionTemplateRef = "demandSqlSessionTemplate")
public class DemandDataSourceConfig {

    /**
     * 扫描application为druid.datasource的前缀,生成Druid数据源
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "druid.datasource")
    public DataSource demandDataSource() {
        return new DruidDataSource();
    }

    /**
     * 创建SqlSessionFactory 利用Qualifier注解指定招聘需求的数据源
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory demandSqlSessionFactory(
            @Qualifier("demandDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
      	// VFS是文件虚拟化,这个看自己项目需不需要打开
        bean.setVfs(SpringBootVFS.class);
        // 配置configuration
        tk.mybatis.mapper.session.Configuration configuration = new tk.mybatis.mapper.session.Configuration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        // 会自动映射任意复杂的结果集(无论是否嵌套)
        configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);
        // 采用驼峰式命名方法
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(
                "classpath*:com/recruitment/infrastructure/mapper/config/demand/*.xml"));
        return bean.getObject();
    }

    /**
     * 配置事务
     * @param dataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager demandTransactionManager(
            @Qualifier("demandDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 配置sqlSession模板
     * @param sqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionTemplate demandSqlSessionTemplate(
            @Qualifier("demandSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

(4)修改对应Mapper的包名,在我的这个项目中,我在mapper.generate下新增了recruitment和demand两个文件夹,MapperScan通过扫描generate下不同的包名来区分不同的数据源

P.S 两个配置时遇到的Bug

(1)如果启动后业务逻辑代码提示Mybatis Invalid statement报错,那么请查看自己代码中有没有设置MapperLocation,单数据源中不需要设置MapperLocation,但是多数据源一定要set这个值。

(2)如果Application启动后提示有三个数据源的bean,而代码中只支持一个单例bean的时候,那么请在启动类上排除掉自动加载单数据源的类,也就是上文中所说的DataSourceAutoConfiguration这个类,如果测业务时只加载一个数据源的时候,也是这个原因。

(3)多说一句,一定要注意扫包时的包名路径,很重要,如果配置不对也是无法扫描到对应路径的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值