java通过注解实现分表详解
作者:LeoLi_4
这篇文章主要为大家详细介绍了java如何通过注解实现分表,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
写在前面
在业务开发中,需要根据不同的渠道存储产品销售信息,由于单个渠道数据量比较大,放在一个表中存储不合适,需要针对每个渠道单独存储。
代码实现
定义注解和切面
定义注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DynamicTable {
/**
* 需要分割的表名
* @return
*/
String tableName();
/**
* 后缀key
* @return
*/
String separateKey();
}
切面处理逻辑
@Aspect
@Component
@Slf4j
public class DynamicTableAspect {
/**
* 用于SpEL表达式解析.
*/
private SpelExpressionParser parser = new SpelExpressionParser();
/**
* 用于获取方法参数定义名字.
*/
private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
private static final String TABLE_NAME = "tableName";
private static final String TABLE_SUFFIX = "tableSuffix";
/**
* 以注解为切点
*/
@Pointcut("@annotation(com.leoli04.DynamicTable)")
public void dynamicTable() {
}
@Around("dynamicTable()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Method method = methodSignature.getMethod();
if(method.isAnnotationPresent(DynamicTable.class)){
DynamicTable dynamicTable = (DynamicTable) method.getAnnotation(DynamicTable.class);
String key = dynamicTable.separateKey();
// 获取参数
Object[] args = joinPoint.getArgs();
Expression expression = parser.parseExpression(key);
// 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组
String[] paramNames = nameDiscoverer.getParameterNames(method);
// spring的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
// 给上下文赋值
for (int i = 0; i < args.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
put(TABLE_NAME, dynamicTable.tableName());
put(TABLE_SUFFIX, expression.getValue(context));
}});
Object proceed = joinPoint.proceed();
RequestDataHelper.removeRequestData();
return proceed;
}else{
Object proceed = joinPoint.proceed();
return proceed;
}
}
}
mybatis拦截器
上面代码在处理切面逻辑中有如下代码:
RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
put(TABLE_NAME, dynamicTable.tableName());
put(TABLE_SUFFIX, expression.getValue(context));
}});
Object proceed = joinPoint.proceed();
RequestDataHelper.removeRequestData();
这段其实是在代码逻辑中设置了上下面,切面逻辑处理完了之后,再把上下文内容去除。目的是为了给mybatis拦截器使用当前请求的上下文内容。
拦截器内部利用的是是mubatis动态表名,内容如下:
@Configuration
@Slf4j
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 添加分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 动态表名插件
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
// 获取参数方法
Map<String, Object> paramMap = RequestDataHelper.getRequestData();
if (CollectionUtils.isNotEmpty(paramMap)) {
var tableNameParam = (String) paramMap.get("tableName");
paramMap.forEach((k, v) -> log.info(k + "----" + v));
if(tableNameParam.equals(tableName)){
// 获取传递的参数
String tableSuffix = (String) paramMap.get("tableSuffix");
if(StringUtils.isBlank(tableSuffix)){
return tableName;
}else{
// 组装动态表名
return tableName + "_" + tableSuffix;
}
}
}
return tableName;
});
mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
return mybatisPlusInterceptor;
}
}
到此这篇关于java通过注解实现分表详解的文章就介绍到这了,更多相关java分表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
