MybatisPlus多数据源配置
采用AOP思想,对DataSource注解进行动态切换,核心思想是依靠 继承AbstractRoutingDataSource,重写determineCurrentLookupKey()方法,在该方法中使用DatabaseContextHolder获取当前线程的dataSource。
首先要在配置文件中配置不同的数据源。
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: datasource: druid: dianshang: driver-class-name: oracle.jdbc.OracleDriver username: xxx password: xxx url: jdbc:oracle:thin:@//10.21.1.18:1531/oradev pos: driver-class-name: oracle.jdbc.OracleDriver username: xxx password: xxx url: jdbc:oracle:thin:@//10.1.8.58:1521/orcl
|
在项目中创建如下文件

首先,编写DynamicDataSource类集成AbstractRoutingDataSource,重写determineCurrentLookupKey方法,该方法主要作用是选择数据源的key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); }
@Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSourceType(); } }
|
其次自定义@DataSource注解,在需要切换数据的Dao添加此注解
1 2 3 4 5 6 7 8 9
|
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String name() default ""; }
|
配置AOP切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Aspect @Component public class DataSourceAspect {
@Pointcut("@annotation(com.xxx.aspect.DataSource)") public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class); if(dataSource == null){ DataSourceHolder.setDataSourceType(dataSource.name()); } try { return point.proceed(); } finally { DataSourceHolder.clearDataSource(); } } }
|
配置DataSourceHolder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class DataSourceHolder {
private static final ThreadLocal<String> DATA_SOURCE = new ThreadLocal<>();
public static void setDataSourceType(String type) { DATA_SOURCE.set(type); }
public static String getDataSourceType() { return DATA_SOURCE.get(); }
public static void clearDataSourceType() { DATA_SOURCE.remove(); } }
|
在项目的配置包中添加配置类
添加数据源配置DataSourceConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Configuration public class DataSourceConfig {
@Bean @ConfigurationProperties(prefix = "spring.datasource.druid.dianshang") public DruidDataSource dataSource1() { return DruidDataSourceBuilder.create().build(); }
@Bean @ConfigurationProperties(prefix = "spring.datasource.druid.pos") public DruidDataSource dataSource2() { return DruidDataSourceBuilder.create().build(); }
@Primary @Bean(name = "dynamicDataSource") public DynamicDataSource dataSource(@Qualifier("dataSource1") DataSource dataSource1, @Qualifier("dataSource2") DataSource dataSource2) { Map<Object, Object> targetDataSources = new HashMap<>(16); targetDataSources.put("dianshang", dataSource1); targetDataSources.put("pos", dataSource2); return new DynamicDataSource(dataSource1, targetDataSources); } }
|
最后配置启动类
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) @MapperScan(basePackages = "com.xxx.mapper")
@Import({DataSourceConfig.class}) public class StartApp { public static void main(String[] args) { SpringApplication.run(StartApp.class); } }
|
如果配了mybatisPlus,需要更改其中的一些配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class MybatisPlusConfig {
@Bean public OracleKeyGenerator oracleKeyGenerator() { return new OracleKeyGenerator(); }
@Bean(name = "mybatisTransactionManager") @Primary public DataSourceTransactionManager testTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
|
之后在写Mybatis的mapper接口时用注解声明要使用的数据源就可以实现动态切换啦
1 2 3 4
| public interface Mapper { @DataSource(name = "pos") String querySkuIdByBarcode(@Param("barcode") String barcode); }
|