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

发布时间:2026/8/14 5:32:16

mybatis动态表名(不使用xml,不手写sql)
这是为了动态分表做的一个功能可以实现表名的动态增加/查询我这边会将添加表的时候录入一个表信息中后续查询的时候会将这个表查询数据这样可以防止一张表数据量过多导致后续维护数据的时候可以根据指标查询对应的数据下面是实现代码pom可能还缺了点依赖我这边使用的是springboot3mybatisplus有需要的可以自己改一下就能用了dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-spring-boot3-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-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)DataToStringBuilderNoArgsConstructorAllArgsConstructorpublicclassTIndexValueDOimplementsSerializable{TableId(typeIdType.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{privatestaticfinalThreadLocalStringINDEX_CODE_HOLDERnewThreadLocal();/** * 设置当前请求的指标代码 */publicstaticvoidsetIndexCode(StringindexCode){INDEX_CODE_HOLDER.set(indexCode);}/** * 获取当前请求的指标代码 */publicstaticStringgetIndexCode(){returnINDEX_CODE_HOLDER.get();}/** * 清除 */publicstaticvoidclear(){INDEX_CODE_HOLDER.remove();}}拦截器 interceptorpackagecom.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{// 这个就是它的表名只有是这个表名的时候才会动态分表publicstaticfinalStringPLACEHOLDERt_index_placeholder;privatefinalDynamicTableResolverresolver;publicDynamicIndexValueInnerInterceptor(DynamicTableResolverresolver){this.resolverresolver;}OverridepublicvoidbeforePrepare(StatementHandlersh,Connectionconnection,IntegertransactionTimeout){BoundSqlboundSqlsh.getBoundSql();StringsqlboundSql.getSql();if(sqlnull||!sql.contains(PLACEHOLDER)){return;}StringindexCodeDynamicIndexValueContextHolder.getIndexCode();// 获取动态表名Stringresolvedresolver.resolve(indexCode);if(resolved!null!resolved.isEmpty()){// 将mybatis生成的表名替换成真实表名查询StringnewSqlsql.replace(PLACEHOLDER,resolved);MetaObjectmetaObjectSystemMetaObject.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 */AutoConfigurationConditionalOnClass(MybatisPlusInterceptor.class)publicclassDynamicTableAutoConfiguration{BeanpublicDynamicIndexValueInnerInterceptordynamicIndexValueInnerInterceptor(MybatisPlusInterceptorinterceptor,DynamicTableResolverresolver){DynamicIndexValueInnerInterceptorinnernewDynamicIndexValueInnerInterceptor(resolver);ListInnerInterceptorinnersnewArrayList(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{ListTIndexValueDOqueryDataListByParams(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 */ServiceValidatedpublicclassTIndexValueServiceImplimplementsTIndexValueService{ResourceprivateTIndexValueMappertIndexValueMapper;OverridepublicListTIndexValueDOqueryDataListByParams(StringindexCode,LocalDate[]pubdate){if(StrUtil.isBlank(indexCode))returnCollections.emptyList();if(pubdatenull)pubdatenewLocalDate[]{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 */MapperpublicinterfaceTIndexValueMapperextendsBaseMapperXTIndexValueDO{defaultListTIndexValueDOselectIndexCodeList(StringindexCode,LocalDate[]pubdate){returnselectList(newLambdaQueryWrapperXTIndexValueDO().eq(TIndexValueDO::getIndexCode,indexCode).betweenIfPresent(TIndexValueDO::getPubDate,pubdate).orderByDesc(TIndexValueDO::getPubDate));}}实际调用AutowiredprivateTIndexValueServicetIndexValueService;ListTIndexValueDOtIndexValueDOStIndexValueService.queryDataListByParams(indexCode,null);System.out.println(tIndexValueDOS);按照上面的方法我们就实现了动态表的实现这里有个问题如果是动态数据源的话就不能这样了得用其他方式主要实现是 DynamicTableResolver 的 resolve 方法这样也处理之后也能节省点开发成本了不过我上面没有添加建表逻辑需要的可以自己实现一下大致流程都是差不多的就新建一个 TIndexValueDO 一摸一样的就行转载请注明原文链接点个关注谢谢大家支持

相关新闻

【TongHttpServer抓包工具-nettool的使用】

【TongHttpServer抓包工具-nettool的使用】

2026/8/14 5:22:16

nettool的使用 netool是一个小巧的抓包工具,总共大小只有20K,不依赖任何第三方库,能解析HTTP请求。可以用来抓取浏览器->THS的HTTP请求或THS->TongWeb的请求。 经常有客户问单独访问TongWeb正常,通过THS代理后就不正常了…

数据库应用程序的可视化设计

数据库应用程序的可视化设计

2026/8/14 5:22:16

学习目标: C#数据库应用程序的开发环境的构成服务器资源管理器类型化数据集创建简单的数据库应用程序水晶报表 Notes: 类型化数据集利用服务器资源管理器建立数据连接 利用服务器资源管理器可执行的任务如下: 1)打开数据连接。 2)…

Google Pixel 11 Pro Fold 与三星 Galaxy Z Fold 8 大比拼,谁更值得买?

Google Pixel 11 Pro Fold 与三星 Galaxy Z Fold 8 大比拼,谁更值得买?

2026/8/14 5:22:16

Google 与三星夏季新品盘点如今 Google 和三星都举办了年度夏季活动,是时候盘点一下两家公司各自推出的产品了。两家都发布了新一代的书本式折叠屏手机,但三星推出了与众不同的 Samsung Galaxy Z Fold 8,它比以往的机型更短更宽。这款手机配置…

Typora图片布局进阶:用HTML/CSS实现多图并排与网格排版

Typora图片布局进阶:用HTML/CSS实现多图并排与网格排版

2026/8/14 6:42:19

1. 项目概述:为什么我们需要在Typora中控制图片布局?如果你和我一样,长期使用Typora作为主力Markdown编辑器,那你一定遇到过这个痛点:当你想在文档里展示一组对比图、一组操作步骤的截图,或者一个产品的多角…

成组链接法:Linux文件系统空闲磁盘块管理的高效算法解析

成组链接法:Linux文件系统空闲磁盘块管理的高效算法解析

2026/8/14 6:42:19

1. 项目概述:从“盘符”到“超级块”,理解文件系统的基石如果你用过Windows,肯定对C盘、D盘这些盘符不陌生。在Linux下,你可能更熟悉/dev/sda1、/dev/sdb2这样的设备名。但你是否想过,操作系统是如何知道一个500GB的硬…

FreeDetect免费查重官网功能详解|权威论文检测服务平台

FreeDetect免费查重官网功能详解|权威论文检测服务平台

2026/8/14 6:42:19

一、平台概述:专业合规的一站式学术服务平台 FreeDetect又称Free查重,是面向本科、专科、硕博研究生、科研学者、期刊投稿作者及职称论文撰写人员的综合性学术检测平台。平台坚守合规学术服务准则,直连各大官方检测API,所有检测报…

Mac打印提示Filter failed?一文详解CUPS打印系统故障排查与修复

Mac打印提示Filter failed?一文详解CUPS打印系统故障排查与修复

2026/8/14 6:42:19

1. 问题初探:当MAC打印弹出“Filter failed” 如果你在Mac上点击打印,满怀期待地等待纸张吐出,结果却只等来一个冷冰冰的“Filter failed”(过滤器失败)的错误提示,那种感觉确实很糟心。这个问题在Mac用户中…

TeXpresso高级技巧:自定义渲染参数与优化编译性能的实用方法

TeXpresso高级技巧:自定义渲染参数与优化编译性能的实用方法

2026/8/14 6:42:19

TeXpresso高级技巧:自定义渲染参数与优化编译性能的实用方法 【免费下载链接】texpresso TeXpresso: live rendering and error reporting for LaTeX 项目地址: https://gitcode.com/gh_mirrors/te/texpresso TeXpresso作为一款专注于LaTeX实时渲染和错误报告…

重庆营销网站建设公司排名深度解析:为什么选对人比选便宜更重要

重庆营销网站建设公司排名深度解析:为什么选对人比选便宜更重要

2026/8/14 6:32:18

在这个数字化转型的浪潮里,许多重庆的企业老板和业务负责人都有一个共同的痛点:想做个好网站,却总被忽悠。以前大家可能觉得有个网页展示一下公司信息就万事大吉了,但现在时代变了,流量贵得吓人,获客成本越来越高,网站不再仅仅是一个线上的“名片”,而是企业获取客户、…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/13 11:01:28

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/11 8:44:43

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/13 17:17:06

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

大连网站建设找简维科技:为您打造懂业务更懂用户的数字化转型引擎

大连网站建设找简维科技:为您打造懂业务更懂用户的数字化转型引擎

2026/8/14 0:01:53

在这个数字化浪潮席卷全球的今天,企业想要在激烈的市场竞争中站稳脚跟,拥有一张好看的“数字名片”已经远远不够了。很多老板在刚开始接触互联网业务时,都有一个共同的困惑:为什么我花了钱建的网站,就像是在真空中自嗨?访客进来转了两圈就跑了,线索石沉大海,甚至连客服…

临沂网站建设铭镇:深耕本土数字生态,以匠心铸就企业品牌核心竞争力

临沂网站建设铭镇:深耕本土数字生态,以匠心铸就企业品牌核心竞争力

2026/8/14 0:01:54

在这个流量为王、视觉至上的互联网时代,对于临沂乃至整个山东乃至全国的传统中小企业来说,拥有一张精美的“数字名片”早已不再是可选项,而是生存的必答题。每当夜幕降临,沂河两岸灯火辉煌,物流之都的喧嚣逐渐沉淀为对未来的思考。我们常常听到老板们在茶余饭后探讨:为什…

Flutter与OpenHarmony实现剧本杀组队表单开发实战

Flutter与OpenHarmony实现剧本杀组队表单开发实战

2026/8/14 0:01:54

1. 项目概述在移动应用开发领域,跨平台框架Flutter因其高效的开发体验和出色的性能表现,已经成为众多开发者的首选。而OpenHarmony作为新兴的操作系统平台,其开放性和灵活性为开发者提供了全新的可能性。本文将聚焦于一个实际应用场景——剧本…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/8 5:07:31

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/9 13:42:46

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/8 2:30:15

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…