springboot mybatis plus多數據源輕松搞定(下)


springboot mybatis plus多數據源輕松搞定 (上) 中我們使用了分包的方式實現了一個springboot項目中多個數據源的調用。也對指出了最大的缺點就是不能靈活自由的切換數據源。那么這一篇中,我們探討一下動態的實現多數據源的方式。可以實現隨心所欲的切換數據源。

基礎的配置

  1. 數據源的yml配置和上一結一樣,就不在贅述了。
  2. 建立一個枚舉類來標識兩個數據源
public enum DataSourceType {
    emanage,ehr
}

建立一個線程和數據源之間的關聯類

public class DataBaseContextHolder {
    private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
    public static void setDataSourceType(DataSourceType type)
    {
        if(type == null)
        {
            throw new NullPointerException();
        }

        contextHolder.set(type);
    }
    public static DataSourceType getDataSourceType()
    {
        DataSourceType type = contextHolder.get();
        if(type == null)
        {
            //確定一個默認數據源
            return DataSourceType.emanage;
        }
        return type;
    }
    
    public static void clearDataSrouceType()
    {
        contextHolder.remove();
    }
}

代碼比較簡單。就是當我們設置一個Mapper是通過那個數據源去訪問數據的時候,把設置的參數保存在contextHolder中,為了處理線程安全,采用ThreadLocal的方式。

定義動態數據源

public class DynamicDataSource extends AbstractRoutingDataSource {
 
    @Override
    protected Object determineCurrentLookupKey() {
 
        return DataBaseContextHolder.getDataSourceType();
    }
}

定義多數據源

@Configuration
@MapperScan("com.emanage.ehr.mapper")
public class DataSourceConfig {

    @Autowired
    private Environment env;

    @Bean(name = "datasource1")
    @ConfigurationProperties(prefix = "spring.datasource.emanage")
    public DruidDataSource druidDataSource1()
    {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.ehr")
    public DruidDataSource druidDataSource2()
    {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public DynamicDataSource dynamicDataSource(@Qualifier("datasource1") DruidDataSource ds1,
                                               @Qualifier("datasource2")  DruidDataSource ds2)
    {
        Map<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put(DataSourceType.emanage, ds1);
        targetDataSource.put(DataSourceType.ehr, ds2);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSource);
        dataSource.setDefaultTargetDataSource(ds1);
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {

        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        // 指定數據源
        bean.setDataSource(dynamicDataSource);
        bean.setMapperLocations(resolver.getResources("classpath*:mapper/**Mapper.xml"));

        return bean.getObject();
    }
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {

        return new DataSourceTransactionManager(dynamicDataSource);
    }

}

使用數據源

在調用mapper之前,在service中執行以下代碼,可以靈活的切換數據源。

DataBaseContextHolder.setDataSourceType(DataSourceType.emanage); 
DataBaseContextHolder.setDataSourceType(DataSourceType.ehr); 

優化升級

感覺在sevrice中調用這些代碼太過繁瑣,可以自己定義兩個注解。

public @interface DataSourceEmanage{}
public @interface DataSourceEHr{}

然后建立一個aop類讓在有些注解的mapper類執行之前,先執行相應的數據源切換。

@Aspect
@Component
public class DataSourceAop {
    @Before("@annotation(com.example.demo3.config.DataSourceEmanage)")
    public void setEmanageDataSource()
    {
        DataBaseContextHolder.setDataSourceType(DataSourceType.emanage);
    }

    @Before("@annotation(com.example.demo3.config.DataSourceEhr)")
    public void setEhrDataSource()
    {
        DataBaseContextHolder.setDataSourceType(DataSourceType.ehr);
    }
}

只需要在mapper對應的方法上面設置注解,就可以很靈活的實現不同的方法調用不同的數據源。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM