MybatisPlus分表
Id分表
- 注解
@Target({ ElementType.METHOD })
@Retention(RUNTIME)
@Documented
public @interface VoteTenantId {
/**
* 拦截方法之上,EL表达式
* @return EL表达式
*/
String value() default "";
}
- 拦截器
@Component
@Aspect
public class VoteTenantIdAop {
@Before(value = "@annotation(com.hccake.extend.mybatis.plus.annotation.VoteTenantId)")
public void beforeCheckout(JoinPoint joinPoint) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),
signature.getMethod().getParameterTypes());
VoteTenantId voteTenantId = method.getAnnotation(VoteTenantId.class);
Object[] args = joinPoint.getArgs();
String result = parseExpression(voteTenantId.value(), method, args);
BaseIdDivideTableNameParser.setId(Integer.valueOf(result));
}
private String parseExpression(String expressionString, Method method, Object[] args) {
// 获取被拦截方法参数名列表
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] paramNameArr = discoverer.getParameterNames(method);
// SPEL解析
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < Objects.requireNonNull(paramNameArr).length; i++) {
context.setVariable(paramNameArr[i], args[i]);
}
return parser.parseExpression(expressionString).getValue(context, String.class);
}
}
- 具体实现
public abstract class BaseIdDivideTableNameParser implements TableNameHandler {
private static final ThreadLocal<Integer> ID = new ThreadLocal<>();
public static void setId(Integer idValue) {
ID.set(idValue);
}
@Override
public String dynamicTableName(String sql, String tableName) {
Integer table = ID.get();
// 这里清除ThreadLocal的值,防止线程复用出现问题
ID.remove();
return tableName + tableName(table);
}
/**
* 划分分表规则,由子类实现
* @param tenantId tenantId
* @return tableName
*/
public abstract String tableName(Integer tenantId);
}
@Service
public class DivideTableName extends BaseIdDivideTableNameParser {
@Override
public String tableName(Integer tenantId) {
return DivideRule.customerInfoRule(tenantId);
}
}
- 引用
@Component
@RequiredArgsConstructor
public class MybatisPlusInterceptorConfig {
private final BaseIdDivideTableNameParser baseIdDivideTableNameParser;
/**
* MybatisPlusInterceptor 插件,默认提供分页插件</br>
* 如需其他MP内置插件,则需自定义该Bean
* @return MybatisPlusInterceptor
*/
@Bean
@ConditionalOnMissingBean(MybatisPlusInterceptor.class)
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
HashMap<String, TableNameHandler> map = new HashMap<>(8);
// 这里为不同的表设置对应表名处理器
map.put("t_message_record", new TimeTableNameParser());
map.put("t_customer_info", baseIdDivideTableNameParser);
dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
时间分表
- 实现·
public class TimeTableNameParser implements TableNameHandler {
@Override
public String dynamicTableName(String sql, String tableName) {
LocalDate date = LocalDate.now();
String table = "_" + date.format(DateTimeFormatter.ofPattern("yyyy_MM"));
return tableName + table;
}
}