Spring Boot 整合多数据源,这才叫优雅~(二)

love374
发布于 2022-7-8 17:28
浏览
0收藏

 

因此我们在自定义的配置类中定义如下配置即可:

/**
     * @Bean:向IOC容器中注入一个Bean
     * @ConfigurationProperties:使得配置文件中以spring.datasource为前缀的属性映射到Bean的属性中
     * @return
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource dataSource(){
        //做一些其他的自定义配置,比如密码加密等......
        return new DruidDataSource();
    }

“以上介绍了两种数据源的配置方式,第一种比较简单,第二种适合扩展,按需选择。”
整合Mybatis
Spring Boot 整合Mybatis其实很简单,简单的几步就搞定,首先添加依赖:

<dependency>
     <groupId>org.mybatis.spring.boot</groupId>
     <artifactId>mybatis-spring-boot-starter</artifactId>
     <version>2.0.0</version>
</dependency>

第二步找到自动配置类MybatisAutoConfiguration,有如下一行代码:

@EnableConfigurationProperties(MybatisProperties.class)

“老套路了,全局配置文件中配置前缀为mybatis的配置将会映射到该类中的属性。”
可配置的东西很多,比如XML文件的位置、类型处理器等等,如下简单的配置:

mybatis.type-handlers-package=com.demo.typehandler
mybatis.configuration.map-underscore-to-camel-case=true

如果需要通过包扫描的方式注入Mapper,则需要在配置类上加入一个注解:@MapperScan,其中的value属性指定需要扫描的包。

“直接在全局配置文件配置各种属性是一种比较简单的方式,其实的任何组件的整合都有不少于两种的配置方式,下面来介绍下配置类如何配置。”
MybatisAutoConfiguration自动配置类有如下一断代码:

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {}

“@ConditionalOnMissingBean和@Bean真是老搭档了,意味着我们又可以覆盖,只需要在IOC容器中注入SqlSessionFactory(Mybatis六剑客之一生产者)。”
在自定义配置类中注入即可,如下:

 /**
     * 注入SqlSessionFactory
     */
    @Bean("sqlSessionFactory1")
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/**/*.xml"));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // 自动将数据库中的下划线转换为驼峰格式
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setDefaultFetchSize(100);
        configuration.setDefaultStatementTimeout(30);
        sqlSessionFactoryBean.setConfiguration(configuration);
        return sqlSessionFactoryBean.getObject();
    }

 

“以上介绍了配置Mybatis的两种方式,其实在大多数场景中使用第一种已经够用了,至于为什么介绍第二种呢?当然是为了多数据源的整合而做准备了。”
在MybatisAutoConfiguration中有一行很重要的代码,如下:

@ConditionalOnSingleCandidate(DataSource.class)

“@ConditionalOnSingleCandidate这个注解的意思是当IOC容器中只有一个候选Bean的实例才会生效。”
这行代码标注在Mybatis的自动配置类中有何含义呢?下面介绍,哈哈哈~ 

多数据源如何整合?
上文留下的问题:为什么的Mybatis自动配置上标注如下一行代码:

@ConditionalOnSingleCandidate(DataSource.class)

“以上这行代码的言外之意:当IOC容器中只有一个数据源DataSource,这个自动配置类才会生效。”
哦?照这样搞,多数据源是不能用Mybatis吗?

可能大家会有一个误解,认为多数据源就是多个的DataSource并存的,当然这样说也不是不正确。

“多数据源的情况下并不是多个数据源并存的,Spring提供了AbstractRoutingDataSource这样一个抽象类,使得能够在多数据源的情况下任意切换,相当于一个动态路由的作用,作者称之为动态数据源。因此Mybatis只需要配置这个动态数据源即可。”
什么是动态数据源?
动态数据源简单的说就是能够自由切换的数据源,类似于一个动态路由的感觉,Spring 提供了一个抽象类AbstractRoutingDataSource,这个抽象类中哟一个属性,如下:

private Map<Object, Object> targetDataSources;

“targetDataSources是一个Map结构,所有需要切换的数据源都存放在其中,根据指定的KEY进行切换。当然还有一个默认的数据源。”
AbstractRoutingDataSource这个抽象类中有一个抽象方法需要子类实现,如下:

protected abstract Object determineCurrentLookupKey();

“determineCurrentLookupKey()这个方法的返回值决定了需要切换的数据源的KEY,就是根据这个KEY从targetDataSources取值(数据源)。”

数据源切换如何保证线程隔离?
数据源属于一个公共的资源,在多线程的情况下如何保证线程隔离呢?不能我这边切换了影响其他线程的执行。

“说到线程隔离,自然会想到ThreadLocal了,将切换数据源的KEY(用于从targetDataSources中取值)存储在ThreadLocal中,执行结束之后清除即可。”

单独封装了一个DataSourceHolder,内部使用ThreadLocal隔离线程,代码如下:

/**
 * 使用ThreadLocal存储切换数据源后的KEY
 */
public class DataSourceHolder {

    //线程  本地环境
    private static final ThreadLocal<String> dataSources = new InheritableThreadLocal();

    //设置数据源
    public static void setDataSource(String datasource) {
        dataSources.set(datasource);
    }

    //获取数据源
    public static String getDataSource() {
        return dataSources.get();
    }

    //清除数据源
    public static void clearDataSource() {
        dataSources.remove();
    }
}

 

文章转自公众号:码猿技术专栏

已于2022-7-8 17:28:10修改
收藏
回复
举报
回复
    相关推荐