1. add jars
2.? init many datasources
@Slf4j
@Component
public class CommandAddSourceimplements CommandLineRunner {
@Autowired
? ? private DefaultDataSourceCreatordataSourceCreator;
@Autowired
? ? private DataSourcedataSource;
@Autowired
? ? private MasterMappermasterMapper;
@Override
? ? public void run(String... args)throws Exception {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource)dataSource;
List masters =masterMapper.queryAllMaster();
masters.forEach(it -> {
DataSourceProperty dataSourceProperty =new DataSourceProperty();
BeanUtils.copyProperties(it, dataSourceProperty);
DataSource dataSource =dataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(it.getPoolName(), dataSource);
});
ds.getDataSources().keySet().forEach(log::info);
}
}
3.? Interceptor table rules
@Slf4j
@Component
public class DynamicInterceptorimplements HandlerInterceptor {
@Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
String id = request.getParameter("id");
long hash = Long.parseLong(id) %100;
System.out.println(hash);
String dsKey ="master";
/**
? ? ? ? * 具体在那个库里 可以 配置在db 中? 比如 shard01 库:? table_00 --> table_10
? ? ? ? * 具体在那个库里 可以 配置在db 中? 比如 shard02 库:? table_11 --> table_20
? ? ? ? * 根据id 可以判断具体的 库
? ? ? ? */
? ? ? ? if (0 <= hash && hash <=50) {
dsKey ="shard01";
}else if (51 <= hash) {
dsKey ="shard02";
}
//hash 值 指向具体的 table? table 可以用 存储过程创建
? ? ? ? String hashStr = StringUtils.leftPad(String.valueOf(hash),2,'0');
OperatorHolder.setTableExt(hashStr);
log.info("经过多数据源filter,dsKey={}", dsKey);
//执行
? ? ? ? DynamicDataSourceContextHolder.push(dsKey);
return true;
}
@Override
? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
OperatorHolder.clearOperator();
DynamicDataSourceContextHolder.poll();
}
}
@Configuration
@RequiredArgsConstructor
public class MyInterceptorConfigextends WebMvcConfigurationSupport {
private final DynamicInterceptordynamicInterceptor;
@Override
? ? protected void addInterceptors(InterceptorRegistry registry) {
// 将上面自定义好的拦截器添加进去。
? ? ? ? registry.addInterceptor(dynamicInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
4.? dynamic table
public class OperatorHolder {
private static final ThreadLocaloperatorThreadLocal =new ThreadLocal<>();
//调用此方法在SpringSecurity中设置当前登录的用户信息
? ? public static void setTableExt(String tableExt) {
operatorThreadLocal.set(tableExt);
}
public static StringgetTableExt() {
return operatorThreadLocal.get();
}
public static void clearOperator() {
operatorThreadLocal.remove();
}
}
public class DynamicTableNameHandlerimplements TableNameHandler {
private final ListtableNames;
//构造函数,构造动态表名处理器的时候,传递tableNames参数
? ? public DynamicTableNameHandler(String... tableNames) {
this.tableNames = Arrays.asList(tableNames);
}
@Override
? ? public StringdynamicTableName(String sql, String tableName) {
String tableExt = OperatorHolder.getTableExt();
if (this.tableNames.contains(tableName) && Objects.nonNull(tableExt)) {
return tableName + tableExt;
}else {
return tableName;
}
}
}
@Configuration
@MapperScan("org.example.mapper")
public class MybatisPlusConfig {
@Bean
? ? public MybatisPlusInterceptormybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor =new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor =new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler(
//可以传多个表名参数,指定哪些表使用MonthTableNameHandler处理表名称
? ? ? ? ? ? ? ? new DynamicTableNameHandler("student")
);
//以拦截器的方式处理表名称
? ? ? ? interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
//可以传递多个拦截器,即:可以传递多个表名处理器TableNameHandler
//interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
? ? ? ? return interceptor;
}
}
5. testing 。。。