动态数据源
订单迁移TIDB 实现读写分离
目标
准备工作
- 数据源准备
- 动态数据源切换
- 参考
AbstractRoutingDataSource
配置数据源
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
| @Configuration @Component public class DynamicDataSourceConfig {
@Bean @ConfigurationProperties("spring.datasource.master") public DataSource master(){ return DruidDataSourceBuilder.create().build(); }
@Bean @ConfigurationProperties("spring.datasource.slave") public DataSource slave(){ return DruidDataSourceBuilder.create().build(); }
@Bean @Primary public DynamicDataSource dataSource(DataSource master, DataSource slave) { Map<Object, Object> allDataSources = new HashMap<>(); targetDataSources.put("master",master); targetDataSources.put("slave", slave); return new DynamicDataSource(master, allDataSources); } }
|
动态数据源切换
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
| public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> allDataSources) { super.setDefaultTargetDataSource(defaultDataSource); super.setTargetDataSources(allDataSources); super.afterPropertiesSet(); }
@Override protected Object determineCurrentLookupKey() { return getDataSource(); }
public static void setDataSource(String dataSource) { contextHolder.set(dataSource); }
public static String getDataSource() { return contextHolder.get(); }
public static void clearDataSource() { contextHolder.remove(); } }
|
配置切换注解
1 2 3 4 5 6 7
| @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 26 27 28 29 30
| @Aspect @Component public class DataSourceAspect {
@Pointcut("@annotation(xx.xx.xx.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){ DynamicDataSource.setDataSource("master"); }else { DynamicDataSource.setDataSource(dataSource.name()); } try { return point.proceed(); } finally { DynamicDataSource.clearDataSource(); } } }
|
使用方式
1 2 3 4 5 6 7 8
|
@DataSource(name="master") public List<TestUser> getMasterUser(){ QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>(); return testUserMapper.selectAll(queryWrapper.isNotNull("name")); }
|