大师系列-Springboot集成Mybatis多数据源精通攻略

大家项目都喜欢用Mybatis进行集成到springboot中,默认是单数据源的,那如果需要多数据源的时候,需要如何进行操作呢?

主要有几个方面:

(1)数据源的配置

(2)Mybatis插件配置

(3)事务和Mapper扫描配置

其实集成的过程中还是有一些坑的,让我们来细说一下。

配置文件如下,数据库和密码可自行修改

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    wxwork:
      minimum-idle: 10
      idle-timeout: 18000
      maximum-pool-size: 1000
      auto-commit: true
      pool-name: HikariCP-Pool
      max-lifetime: 1800000
      connection-timeout: 300000
      connection-test-query: SELECT 1
      jdbc-url: jdbc:mysql://xxxA/dba?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
      username: xx
      password: xx
      driver-class-name: com.mysql.cj.jdbc.Driver
    wxbill:
      jdbc-url: jdbc:mysql://xx/dbB?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
      username: xx
      password: xx
      driver-class-name: com.mysql.cj.jdbc.Driver
      minimum-idle: 10
      idle-timeout: 18000
      maximum-pool-size: 1000
      auto-commit: true
      pool-name: HikariCP-Pool-Bill
      max-lifetime: 1800000
      connection-timeout: 300000
      connection-test-query: SELECT 1

现在要做的是配置2个数据源,这里也可以多个的,就看自身项目需要

里面的包扫描路径,需要根据自身的项目进行修改

@Configuration
@ConditionalOnProperty(prefix = "spring.datasource.xxA", name = "jdbc-url")
@EnableConfigurationProperties({MybatisProperties.class, PageHelperProperties.class})
@MapperScan(
    basePackages = {"com.xxx.persist.mapper", "com.xxx.mapper"},
    sqlSessionTemplateRef = "wxBillSqlSessionTemplate")
public class WxBillMybatisAutoConfiguration {

  @Bean
  @ConfigurationProperties("spring.datasource.xxxA")
  public HikariDataSource wxBillDataSource() {
    return DataSourceBuilder.create().type(HikariDataSource.class).build();
  }

  @Bean
  public SqlSessionFactory wxBillSessionFactory(MybatisProperties mybatisProperties)
      throws Exception {
    return MybatisUtil.buildSessionFactory(
        wxBillDataSource(), mybatisProperties, "classpath*:xxA.mapper/*.xml");
  }

  @Bean
  public DataSourceTransactionManager wxBillTransactionManager() {
    return new DataSourceTransactionManager(wxBillDataSource());
  }

  @Bean
  public SqlSessionTemplate wxBillSqlSessionTemplate(MybatisProperties mybatisProperties)
      throws Exception {
    return new SqlSessionTemplate(wxBillSessionFactory(mybatisProperties));
  }
}

配置数据库B的数据源

@Configuration
@ConditionalOnProperty(prefix = "spring.datasource.xxB", name = "jdbc-url")
@EnableConfigurationProperties(MybatisProperties.class)
@MapperScan(
    basePackages = {"com.xx.mapper", "com.xx.mapper"},
    sqlSessionTemplateRef = "wxWorkSqlSessionTemplate")
public class WxWorkMybatisAutoConfiguration {

  @Bean
  @Primary
  @ConfigurationProperties("spring.datasource.xxB")
  public HikariDataSource wxWorkDataSource() {
    return DataSourceBuilder.create().type(HikariDataSource.class).build();
  }

  @Bean
  @Primary
  public SqlSessionFactory wxWorkSessionFactory(MybatisProperties mybatisProperties)
      throws Exception {
    return MybatisUtil.buildSessionFactory(
        wxWorkDataSource(), mybatisProperties, "classpath*:mapper/*.xml");
  }

  @Bean
  @Primary
  public DataSourceTransactionManager wxWorkTransactionManager() {
    return new DataSourceTransactionManager(wxWorkDataSource());
  }

  @Bean
  @Primary
  public SqlSessionTemplate wxWorkSqlSessionTemplate(MybatisProperties mybatisProperties)
      throws Exception {
    return new SqlSessionTemplate(wxWorkSessionFactory(mybatisProperties));
  }
}

这么简单就完成了两个数据源的配置,里面有个很重要的方法,MybatisUtil,这里也是解决坑的地方

public class MybatisUtil {

  public static SqlSessionFactory buildSessionFactory(
      DataSource dataSource, MybatisProperties mybatisProperties, String mapLocation)
      throws Exception {
    // 这里需要复制属性
    MybatisProperties localProperties =
        BeanMapper.mapper(mybatisProperties, MybatisProperties.class);

    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setVfs(SpringBootVFS.class);
    bean.setDataSource(dataSource);

    if (StringUtils.hasText(mapLocation)) {
      localProperties.setMapperLocations(mapLocation.split(","));
    }

    if (!ObjectUtils.isEmpty(localProperties.resolveMapperLocations())) {
      bean.setMapperLocations(localProperties.resolveMapperLocations());
    }

    if (localProperties.getConfigurationProperties() != null) {
      bean.setConfigurationProperties(localProperties.getConfigurationProperties());
    }

    Configuration configuration =
        BeanMapper.mapper(localProperties.getConfiguration(), Configuration.class);
    bean.setConfiguration(configuration);

    return bean.getObject();
  }
}

这里查看源码会发现,Configuration这个对象,会跟MapperRegistry有关联,所以这里一定要重新生成一个对象,不然会发现查库时查到另外一个数据库上,大坑啊。

 

很多项目都会集成pageHelper插件,如果按照上面去运行,会发现插件并没有生效,因为都没有进行插件注册

@AllArgsConstructor
@Configuration
@EnableConfigurationProperties({PageHelperProperties.class})
public class PageHelperPluginAutoConfiguration {

  private final List<SqlSessionFactory> sqlSessionFactoryList;
  private final PageHelperProperties pageHelperProperties;

  @PostConstruct
  public void addPageInterceptor() {
    PageInterceptor interceptor = new PageInterceptor();
    Properties properties = new Properties();
    properties.putAll(pageHelperProperties.getProperties());
    interceptor.setProperties(properties);

    for (SqlSessionFactory sqlSessionFactory : this.sqlSessionFactoryList) {
      org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
      if (!this.containsInterceptor(configuration, interceptor)) {
        configuration.addInterceptor(interceptor);
      }
    }
  }

  private boolean containsInterceptor(
      org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {
    try {
      return configuration.getInterceptors().contains(interceptor);
    } catch (Exception ex) {
      return false;
    }
  }
}

插件注册逻辑也很简单,就是找到配置的多个sessionFactory,然后把插件写入进去。

 

最后,肯定是要避开springboot自动配置的数据源,不然启动的时候会报错的

避开方法很简单

@SpringBootApplication(
    scanBasePackages = "com.xxxx",
    exclude = {
      DataSourceAutoConfiguration.class,
      DataSourceTransactionManagerAutoConfiguration.class,
      JdbcTemplateAutoConfiguration.class,
    })

到此为止,所有的多数据源和扫描配置都已经完成

需要注意的就是Mapper和Xml各种一定要分包和分文件夹,避免重复扫描。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值