springboot3 mybatis-plus 分库分表
1. add jars
![](https://img.haomeiwen.com/i2536235/87cf1b7008f9d8fd.png)
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 。。。
![](https://img.haomeiwen.com/i2536235/c47c5e23cd811952.png)