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