springboot+druid+mybatis plus的多数据源配置
思路
- yml中配置多个数据源信息
- 通过AOP切换不同数据源
- 配合mybatis plus使用
POM依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- AOP依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- MyBatisPlus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version> </dependency> <!--Mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <!-- Druid依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
YML配置
spring:
aop:
proxy-target-class: true
auto: true
datasource:
druid:
es:
url: jdbc:mysql://192.168.21.181:3306/jarvis
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
wx:
initialSize: 5
minIdle: 5
maxActive: 20
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://192.168.21.181:3306/jarvis_wx
启动加载多个数据源
package com.jarvis.config; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; 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; @Configuration @EnableTransactionManagement @MapperScan("com.jarvis.task.*.mapper") public class MybatisPlusConfig { /*** * plus 的性能优化 */ @Bean public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); /* <!-- SQL 执行性能分析,开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长 --> */ //performanceInterceptor.setMaxTime(1000); /* <!--SQL是否格式化 默认false--> */ performanceInterceptor.setFormat(false); return performanceInterceptor; } /** * mybatis-plus 分页插件 */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor page = new PaginationInterceptor(); page.setDialectType("mysql"); return page; } @Bean(name = "esDb") @ConfigurationProperties(prefix = "spring.datasource.druid.es" ) public DataSource esDb () { return DruidDataSourceBuilder.create().build(); } @Bean(name = "wxDb") @ConfigurationProperties(prefix = "spring.datasource.druid.wx" ) public DataSource wxDb () { return DruidDataSourceBuilder.create().build(); } /** * 动态数据源配置 * @return */ @Bean @Primary public DataSource multipleDataSource (@Qualifier("esDb") DataSource esDb, @Qualifier("wxDb") DataSource wxDb ) { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map< Object, Object > targetDataSources = new HashMap<>(2); targetDataSources.put(DBTypeEnum.ES.getValue(), esDb ); targetDataSources.put(DBTypeEnum.WX.getValue(), wxDb); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(esDb); return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(esDb(),wxDb())); //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml")); MybatisConfiguration configuration = new MybatisConfiguration(); //configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor() 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; // } }
DBType枚举类
public enum DBTypeEnum { ES("es"), WX("wx"); private String value; DBTypeEnum(String value) { this.value = value; } public String getValue() { return value; } }
动态数据源决策
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { /** * 取得当前使用哪个数据源 * @return */ @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDbType(); } }
设置、获取数据源
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(); } }
AOP实现的数据源切换
import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(-100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高 @Slf4j public class DataSourceSwitchAspect { @Pointcut("execution(* com.jarvis.task.db2es.mapper..*.*(..))") private void jarvisAspect() { } @Pointcut("execution(* com.jarvis.task.dt2db.mapper..*.*(..))") private void jarvisWxAspect() { } @Before("jarvisAspect()") public void jarvisDb() { log.info("切换到ES 数据源..."); DbContextHolder.setDbType(DBTypeEnum.ES); } @Before("jarvisWxAspect()") public void jarvisWxDb () { log.info("切换到WX 数据源..."); DbContextHolder.setDbType(DBTypeEnum.WX); } }
mapper层结构
参考
https://www.jianshu.com/p/ff5af6c59365?utm_source=oschina-app