java通过注解实现分表详解
目录
- 写在前面
- 代码实现
- 定义注解和切面
- myBATis拦截器
写在前面
在业务php开发中,需要根据不同的渠道存储产品销售信息,由于单个渠道数据量比较大,放在一个表中存储不合适,需要针对每个渠道单独存储。
代码实现
定义注解和切面
定义注解
@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 proceephpd = 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()); // 动态表名插件 DynamicTableNameInnerIntercejavascriptptor 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.is编程客栈Blank(tableSuffix)){ return tableName; }else{ // 组装动态表名 return tableName + "_" + tableSuffix; } } } return tjavascriptableName; }); mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor); return mybatisPlusInterceptor; } }
到此这篇关于Java通过注解实现分表详解的文章就介绍到这了,更多相关java分表内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论