springboot+druid+mybatis plus的多數據源配置


https://www.jianshu.com/p/ff5af6c59365

多數據源配置,在我們集成多個系統或者對接的時候經常會用到,結合springboot、druid提供了比較方便的集成方案。

思路:
1、yml中配置多個數據源信息
2、通過AOP切換不同數據源
3、配合mybatis plus使用


1、yml配置

spring: aop: proxy-target-class: true auto: true datasource: druid: db1: url: jdbc:mysql://localhost:3306/eboot username: root password: root driver-class-name: com.mysql.jdbc.Driver initialSize: 5 minIdle: 5 maxActive: 20 db2: url: jdbc:oracle:thin:@192.168.136.222:ORCL username: sa password: sa123456 driver-class-name: oracle.jdbc.OracleDriver initialSize: 5 minIdle: 5 maxActive: 20 db3: url: jdbc:oracle:thin:@192.168.136.223:ORCL username: sb password: sb123456 driver-class-name: oracle.jdbc.OracleDriver initialSize: 5 minIdle: 5 maxActive: 20 

2、啟動加載多個數據源

下面mybatis plus的全局配置被注掉了,因為同樣可以在yml中配置也可以

package com.df.openapi.config; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.baomidou.mybatisplus.MybatisConfiguration; import com.baomidou.mybatisplus.entity.GlobalConfiguration; import com.baomidou.mybatisplus.mapper.LogicSqlInjector; import com.baomidou.mybatisplus.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean; import com.df.openapi.config.db.DBTypeEnum; import com.df.openapi.config.db.DynamicDataSource; import com.df.openapi.config.db.MyMetaObjectHandler; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.type.JdbcType; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * @author 小塵哥 */ @EnableTransactionManagement @Configuration @MapperScan("com.df.openapi.**.mapper.db*") public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setLocalPage(true); return paginationInterceptor; } @Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.druid.db1") public DataSource db1() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.druid.db2") public DataSource db2() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db3") @ConfigurationProperties(prefix = "spring.datasource.druid.db3") public DataSource db3() { return DruidDataSourceBuilder.create().build(); } /** * 動態數據源配置 * * @return */ @Bean @Primary public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2, @Qualifier("db3") DataSource db3) { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DBTypeEnum.db1.getValue(), db1); targetDataSources.put(DBTypeEnum.db2.getValue(), db2); targetDataSources.put(DBTypeEnum.db3.getValue(), db3); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(db2); return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2(),db3())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); //PerformanceInterceptor(),OptimisticLockerInterceptor() //添加分頁功能 sqlSessionFactory.setPlugins(new Interceptor[]{ paginationInterceptor() }); // sqlSessionFactory.setGlobalConfig(globalConfiguration()); return sqlSessionFactory.getObject(); } /* @Bean public GlobalConfiguration globalConfiguration() { GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector()); conf.setLogicDeleteValue("-1"); conf.setLogicNotDeleteValue("1"); conf.setIdType(0); conf.setMetaObjectHandler(new MyMetaObjectHandler()); conf.setDbColumnUnderline(true); conf.setRefresh(true); return conf; }*/ } 

3、DBType枚舉類

package com.df.openapi.config.db; public enum DBTypeEnum { db1("db1"), db2("db2"), db3("db3"); private String value; DBTypeEnum(String value) { this.value = value; } public String getValue() { return value; } } 

4、動態數據源決策

package com.df.openapi.config.db; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDbType(); } } 

5、設置、獲取數據源

package com.df.openapi.config.db; public class DbContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal<>(); /** * 設置數據源 * @param dbTypeEnum */ public static void setDbType(DBTypeEnum dbTypeEnum) { contextHolder.set(dbTypeEnum.getValue()); } /** * 取得當前數據源 * @return */ public static String getDbType() { return (String) contextHolder.get(); } /** * 清除上下文數據 */ public static void clearDbType() { contextHolder.remove(); } } 

6、AOP實現的數據源切換

@Order設置的足夠小是為了讓他先執行

package com.df.openapi.config.db; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * @author 迪富 */ @Component @Order(value = -100) @Slf4j @Aspect public class DataSourceSwitchAspect { @Pointcut("execution(* com.df.openapi.*.mapper.db1..*.*(..))") private void db1Aspect() { } @Pointcut("execution(* com.df.openapi.*.mapper.db2..*.*(..))") private void db2Aspect() { } @Pointcut("execution(* com.df.openapi.*.mapper.db3..*.*(..))") private void db3Aspect() { } @Before("db1Aspect()") public void db1() { log.info("切換到db1 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db1); } @Before("db2Aspect()") public void db2() { log.info("切換到db2 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db2); } @Before("db3Aspect()") public void db3() { log.info("切換到db3 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db3); } } 

7、mapper層結構

 
根據dbx的實現數據源切換.png

8、寫一個service測試一下

可以看到下面的兩個Mapper分別來自db1和db2

package com.df.openapi.system.service.impl; import com.df.openapi.system.entity.PtDict; import com.df.openapi.system.entity.SysDict; import com.df.openapi.system.mapper.db1.PtDictMapper; import com.df.openapi.system.mapper.db2.SysDictMapper; import com.df.openapi.system.service.IDictService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class DictServiceImpl implements IDictService { @Resource private PtDictMapper ptDictMapper; @Resource private SysDictMapper sysDictMapper; @Override public void getById(String id) { PtDict dict = ptDictMapper.selectById("2bf6257fc8fe483c84c1ad7e89d632f6"); SysDict sysDict = sysDictMapper.getById("49"); System.out.println("123"); } } 

9、簡單的單元測試

@RunWith(SpringRunner.class) @SpringBootTest public class OpenApiApplicationTests { @Autowired private IDictService dictService; @Test public void contextLoads() { } @Test public void test() { dictService.getById("1"); } } 

10、測試結果

 
取到兩個數據庫的數據.png

參考上面的方法,可以隨意配置三四五六七八九十個數據源都沒問題,有問題歡迎隨時來撩!



作者:小塵哥
鏈接:https://www.jianshu.com/p/ff5af6c59365
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

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



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