当前位置: 首页 > news >正文

mybatis动态表名(不使用xml,不手写sql)

这是为了动态分表做的一个功能,可以实现表名的动态增加/查询,我这边会将添加表的时候录入一个表信息中,后续查询的时候会将这个表查询数据,这样可以防止一张表数据量过多,导致后续维护数据的时候,可以根据指标查询对应的数据,下面是实现代码

pom

可能还缺了点依赖,我这边使用的是springboot3,mybatisplus,有需要的可以自己改一下就能用了

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency>

实体类

packagecom.ljq.module.indexvalue.dal.dataobject.indexvalue;importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableId;importcom.baomidou.mybatisplus.annotation.TableName;importcom.ljq.dynamic.indexvalue.table.interceptor.DynamicIndexValueInnerInterceptor;importlombok.*;importjava.io.Serializable;importjava.math.BigDecimal;importjava.time.LocalDate;importjava.time.LocalDateTime;/** * 指标值表 DO(动态表名,运行时根据 indexCode 解析) * * @author jianqiang li */// 这个tableName我这边写成一个需要替换的动态表名,可以是任何名称或uuid都可以@TableName(DynamicIndexValueInnerInterceptor.PLACEHOLDER)@Data@ToString@Builder@NoArgsConstructor@AllArgsConstructorpublicclassTIndexValueDOimplementsSerializable{@TableId(type=IdType.AUTO)privateLongid;privateLocalDatepubDate;privateLocalDateTimecollectTime;privateStringindexCode;privateBigDecimalindexValue;privateLocalDateTimecreateTime;privateLocalDateTimeupdateTime;}

resolver

只要实现这个接口,返回真实的表名就能实现动态表名了,为了方便我这边就不实现了,可以按照自己想要的方式来实现即可,返回如 index_base.index_0001,这样格式的字符串就行了,相当于我这边可以把指标值存放在不同的表中了,这个方法中的resolve只是一个简单示例,完全可以自己定义方法参数等等

packagecom.ljq.dynamic.indexvalue.table.resolver;/** * 动态表名解析器接口,根据 indexCode 解析出完整的 schema.tableName * * @author jianqiang li */publicinterfaceDynamicTableResolver{/** * 根据 indexCode 解析完整表名 * * @param indexCode 指标代码 * @return 格式:schema.tableName,例如 db_info_f.t_index_0000003 */Stringresolve(StringindexCode);}

context

由于我这边是更具指标代码来区分表的,所以就得在查询前手动调用一下这个setIndexCode方法,否则这个动态表名就无法生效,如果是按照年月区分的话就完全不需要这个了,直接根据年月来设置即可

packagecom.ljq.dynamic.indexvalue.table.context;/** * 动态指标值表上下文,基于 ThreadLocal 存储当前请求的 indexCode * * @author jianqiang li */publicclassDynamicIndexValueContextHolder{privatestaticfinalThreadLocal<String>INDEX_CODE_HOLDER=newThreadLocal<>();/** * 设置当前请求的指标代码 */publicstaticvoidsetIndexCode(StringindexCode){INDEX_CODE_HOLDER.set(indexCode);}/** * 获取当前请求的指标代码 */publicstaticStringgetIndexCode(){returnINDEX_CODE_HOLDER.get();}/** * 清除 */publicstaticvoidclear(){INDEX_CODE_HOLDER.remove();}}

拦截器 interceptor

packagecom.ljq.dynamic.indexvalue.table.interceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;importcom.ljq.dynamic.indexvalue.table.context.DynamicIndexValueContextHolder;importcom.ljq.dynamic.indexvalue.table.resolver.DynamicTableResolver;importorg.apache.ibatis.executor.statement.StatementHandler;importorg.apache.ibatis.mapping.BoundSql;importorg.apache.ibatis.reflection.MetaObject;importorg.apache.ibatis.reflection.SystemMetaObject;importjava.sql.Connection;/** * 在mybatis层拦截,只要是 PLACEHOLDER 表名的就需要替换成动态表名 * * @author jianqiang li */publicclassDynamicIndexValueInnerInterceptorimplementsInnerInterceptor{// 这个就是它的表名,只有是这个表名的时候才会动态分表publicstaticfinalStringPLACEHOLDER="t_index_placeholder";privatefinalDynamicTableResolverresolver;publicDynamicIndexValueInnerInterceptor(DynamicTableResolverresolver){this.resolver=resolver;}@OverridepublicvoidbeforePrepare(StatementHandlersh,Connectionconnection,IntegertransactionTimeout){BoundSqlboundSql=sh.getBoundSql();Stringsql=boundSql.getSql();if(sql==null||!sql.contains(PLACEHOLDER)){return;}StringindexCode=DynamicIndexValueContextHolder.getIndexCode();// 获取动态表名Stringresolved=resolver.resolve(indexCode);if(resolved!=null&&!resolved.isEmpty()){// 将mybatis生成的表名替换成真实表名查询StringnewSql=sql.replace(PLACEHOLDER,resolved);MetaObjectmetaObject=SystemMetaObject.forObject(boundSql);metaObject.setValue("sql",newSql);}}}

config,注册上面的拦截器使其生效

packagecom.ljq.dynamic.indexvalue.table.config;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;importcom.ljq.dynamic.indexvalue.table.interceptor.DynamicIndexValueInnerInterceptor;importcom.ljq.dynamic.indexvalue.table.resolver.DynamicTableResolver;importorg.springframework.boot.autoconfigure.AutoConfiguration;importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass;importorg.springframework.context.annotation.Bean;importjava.util.ArrayList;importjava.util.List;/** * 注册拦截器 * * @author jianqiang li */@AutoConfiguration@ConditionalOnClass(MybatisPlusInterceptor.class)publicclassDynamicTableAutoConfiguration{@BeanpublicDynamicIndexValueInnerInterceptordynamicIndexValueInnerInterceptor(MybatisPlusInterceptorinterceptor,DynamicTableResolverresolver){DynamicIndexValueInnerInterceptorinner=newDynamicIndexValueInnerInterceptor(resolver);List<InnerInterceptor>inners=newArrayList<>(interceptor.getInterceptors());inners.add(1,inner);interceptor.setInterceptors(inners);returninner;}}

使用

到这里我们就已经把配置都编辑好了,下面我们可以来使用起来了

packagecom.ljq.module.indexvalue.service.indexvalue;importjava.time.LocalDate;importjava.util.*;importcom.ljq.module.indexvalue.controller.admin.indexvalue.vo.*;importcom.ljq.module.indexvalue.dal.dataobject.indexvalue.TIndexValueDO;importjakarta.validation.*;importcom.ljq.framework.common.pojo.PageResult;/** * 指标值表 Service 接口 * * @author jianqiang li */publicinterfaceTIndexValueService{List<TIndexValueDO>queryDataListByParams(StringindexCode,LocalDate[]pubdate);}
packagecom.ljq.module.indexvalue.service.indexvalue;importcn.hutool.core.util.StrUtil;importcom.ljq.dynamic.indexvalue.table.context.DynamicIndexValueContextHolder;importcom.ljq.framework.common.pojo.PageResult;importcom.ljq.framework.mybatis.core.query.LambdaQueryWrapperX;importcom.ljq.module.indexvalue.controller.admin.indexvalue.vo.*;importcom.ljq.module.indexvalue.dal.dataobject.indexvalue.TIndexValueDO;importcom.ljq.module.indexvalue.dal.mysql.indexvalue.TIndexValueMapper;importorg.springframework.stereotype.Service;importjakarta.annotation.Resource;importorg.springframework.validation.annotation.Validated;importjava.math.BigDecimal;importjava.time.LocalDate;importjava.util.*;importcom.ljq.framework.common.util.object.BeanUtils;importstaticcom.ljq.framework.common.exception.util.ServiceExceptionUtil.exception;/** * 指标值表 Service 接口 * * @author jianqiang li */@Service@ValidatedpublicclassTIndexValueServiceImplimplementsTIndexValueService{@ResourceprivateTIndexValueMappertIndexValueMapper;@OverridepublicList<TIndexValueDO>queryDataListByParams(StringindexCode,LocalDate[]pubdate){if(StrUtil.isBlank(indexCode))returnCollections.emptyList();if(pubdate==null)pubdate=newLocalDate[]{null,null};DynamicIndexValueContextHolder.setIndexCode(indexCode);try{returntIndexValueMapper.selectIndexCodeList(indexCode,pubdate);}finally{DynamicIndexValueContextHolder.clear();}}}
packagecom.ljq.module.indexvalue.dal.mysql.indexvalue;importcom.ljq.framework.common.pojo.PageResult;importcom.ljq.framework.mybatis.core.query.LambdaQueryWrapperX;importcom.ljq.framework.mybatis.core.mapper.BaseMapperX;importcom.ljq.module.indexvalue.controller.admin.indexvalue.vo.TIndexValuePageReqVO;importcom.ljq.module.indexvalue.dal.dataobject.indexvalue.TIndexValueDO;importorg.apache.ibatis.annotations.Mapper;importjava.time.LocalDate;importjava.util.List;/** * 指标值表 Mapper * * @author jianqiang li */@MapperpublicinterfaceTIndexValueMapperextendsBaseMapperX<TIndexValueDO>{defaultList<TIndexValueDO>selectIndexCodeList(StringindexCode,LocalDate[]pubdate){returnselectList(newLambdaQueryWrapperX<TIndexValueDO>().eq(TIndexValueDO::getIndexCode,indexCode).betweenIfPresent(TIndexValueDO::getPubDate,pubdate).orderByDesc(TIndexValueDO::getPubDate));}}

实际调用

@AutowiredprivateTIndexValueServicetIndexValueService;List<TIndexValueDO>tIndexValueDOS=tIndexValueService.queryDataListByParams(indexCode,null);System.out.println(tIndexValueDOS);

按照上面的方法我们就实现了动态表的实现,这里有个问题,如果是动态数据源的话就不能这样了,得用其他方式,主要实现是 DynamicTableResolver 的 resolve 方法,这样也处理之后也能节省点开发成本了,不过我上面没有添加建表逻辑,需要的可以自己实现一下,大致流程都是差不多的,就新建一个 TIndexValueDO 一摸一样的就行

转载请注明原文链接,点个关注,谢谢大家支持

http://www.jsqmd.com/news/1389683/

相关文章:

  • 小于电商开放平台-获取订单列表
  • 我就想让计算机识别一瓶可乐,并把他拿起来 (3)
  • AD软件PCB快捷键
  • LaneDetection_End2End项目全解析:从ICCV 2019论文到实战落地
  • 深入解析栈与堆内存:从原理到实战,解决内存不足与泄漏问题
  • DeepSeek V4-Pro 转正:号称追平 Claude Fable 5,但跑分只有一家在说
  • 揭秘叶县建设局网站背后的民生温度与工程品质
  • 智慧建筑管控利器!楼宇自控系统如何实现楼宇长效节能运营
  • 从架构到实践:构建生产级RAG系统的核心模块与演进之路
  • FFmpeg实战:从零构建自适应比特率流媒体(HLS/DASH)
  • AI智能体安全攻防全景:当自主Agent成为黑客的新战场
  • 深入解析福建省亿力电力建设有限公司网站如何成为您电力工程的可靠合作伙伴与行业标杆
  • Steam创意工坊动态壁纸免费下载:3步获取付费壁纸的完整指南
  • 仅需25秒!山东科技大学开发高性能燃料电池阴极:高功率、耐CO₂、稳定运行250小时
  • 系统工程优化与Python实现:煤矿巷道支护建模全解析
  • android源码在线阅读-支持跳转
  • FFmpeg 入门指南:从安装到实战,避开社区版陷阱
  • zerotier局域网组建 笔记
  • Web端Markdown编辑器实现:优化DESIGN.md协作流程的技术方案
  • SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍
  • 拒绝花架子做实体:揭秘兰州营销型网站建设如何让本地企业订单翻倍
  • 强引用,弱引用,软引用,虚引用它们有什么区别?你知道吗?
  • 记录C++ 4
  • 一天内用AI构建Netty MVC框架:探索AI编程的工程实践与边界
  • Ubuntu(Linux系统)安装Vulhub靶场
  • 【高级数字信号处理】超详细指南lab1a:MATLAB 信号采样、频谱分析、非线性削波及混叠现象完全解读【含matlab代码】
  • DeepSeek V4与GPT-5.5实测对比:AI大模型选型指南
  • Windows 10硬盘卡顿终极解决指南:从诊断到优化,告别系统延迟
  • Transformer架构深度解析:从自注意力到编码器层的工程实现
  • 数据倾斜原理及解决方案