手把手教你如何扩展(破解)mybatisplus的sql生成 | 京东云技术团队
mybatisplus 的常用CRUD方法
众所周知,mybatisplus提供了强大的代码生成能力,他默认生成的常用的CRUD方法(例如插入、更新、删除、查询等)的定义,能够帮助我们节省很多体力劳动。
他的BaseMapper
中定义了这些常用的CRUD方法,我们在使用时,继承这个BaseMapper
类就默认拥有了这些能力。
如果我们的业务中,需要类似的通用Sql时,该如何实现呢?
是每个Mapper中都定义一遍类似的Sql吗?
显然这是最笨的一种方法。
此时我们可以借助mybatisplus
这个成熟框架,来实现我们想要的通用Sql。
扩展常用CRUD方法
新增一个通用sql
比如有一个这样的需求,项目中所有表或某一些表,都要执行一个类似的查询,如`SelectByErp`,那么可以这样实现。(这是一个最简单的sql实现,使用时可以根据业务需求实现更为复杂的sql:比如多租户系统自动增加租户id参数、分库分表系统增加分库分表字段条件判断)
-
定义一个
SelectByErp
类,继承AbstractMethod
类,并实现injectMappedStatement
方法 -
定义sql方法名、sql模板、实现sql的拼接组装
/** * 新增一个通用sql */ public class SelectByErp extends AbstractMethod { // 需要查询的列名 private final String erpColumn = "erp"; // sql方法名 private final String method = "selectByErp"; // sql模板 private final String sqlTemplate = "SELECT %s FROM %s WHERE %s=#{%s} %s"; @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { // 获取需要查询的字段名及属性名 TableFieldInfo erpFiled = getErpProperty(tableInfo); // 拼接组装sql SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlTemplate, sqlSelectColumns(tableInfo, false), tableInfo.getTableName(), erpFiled.getColumn(), erpFiled.getProperty(), tableInfo.getLogicDeleteSql(true, false)), Object.class); return this.addSelectMappedStatementForTable(mapperClass, method, sqlSource, tableInfo); } /** * 查询erp列信息 */ private TableFieldInfo getErpProperty(TableInfo tableInfo) { List<TableFieldInfo> fieldList = tableInfo.getFieldList(); TableFieldInfo erpField = fieldList.stream().filter(filed -> filed.getColumn().equals(erpColumn)).findFirst().get(); return erpField; }
3.定义一个sql注入器GyhSqlInjector
,添加SelectByErp
对象
// 需注入到spring容器中 @Component public class GyhSqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 增加 SelectByErp对象,程序启动后自动加载 methodList.add(new SelectByErp()); return methodList; } }
4.定义一个基础MapperGyhBaseMapper
,添加selectByErp
方法
/** * 自定义的通用Mapper */ public interface GyhBaseMapper<T> extends BaseMapper<T> { List<T> selectByErp(String erp); }
5.应用中需要使用该SelectByErp
方法的表,都继承GyhBaseMapper
,那么这些表将都拥有了selectByErp
这个查询方法,程序启动后会自动为这些表生成该sql。
public interface XXXMapper extends GyhBaseMapper<XXXTable>
添加一个mybatisplus已有sql
1.mybatisplus 常用CRUD方法如最上图,这些方法已经默认会自动生成,但mybatisplus其实提供了更多的方法,如下图,只要我们在启动时添加进去,就可以使用了。
2.比如我想使用AlwaysUpdateSomeColumnById
方法,该方法可以在更新时只更新我需要的字段,不进行全字段更新。添加步骤如下。
3.定义一个sql注入器 ,如GyhSqlInjector
,添加AlwaysUpdateSomeColumnById
对象
@Component public class GyhSqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 添加 AlwaysUpdateSomeColumnById 对象 methodList.add(new AlwaysUpdateSomeColumnById()); return methodList; } }
4.定义一个基础Mapper 如GyhBaseMapper
,添加alwaysUpdateSomeColumnById
方法
/** * 自定义的通用Mapper */ public interface GyhBaseMapper<T> extends BaseMapper<T> { int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity); }
5.继承GyhBaseMapper
的其他Mapper,将自动拥有alwaysUpdateSomeColumnById
方法
/** * 自定义的通用Mapper */ public interface GyhBaseMapper<T> extends BaseMapper<T> { int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity); }
6.继承GyhBaseMapper
的其他Mapper,将自动拥有alwaysUpdateSomeColumnById
方法
编辑一个mybatisplus已有sql
1.如果想编辑一个mybatisplus已有sql,比如分库分表系统,执行updateById
操作时,虽然主键Id已确定,但目标表不确定,此时可能导致该sql在多张表上执行,造成资源浪费,并且分库分表字段不可修改,默认的updateById
不能用,需要改造。以下以shardingsphere
分库分表为例。
2.定义一个UpdateByIdWithSharding
类,继承UpdateById
类
public class UpdateByIdWithSharding extends UpdateById { private String columnDot = "`"; private YamlShardingRuleConfiguration yamlShardingRuleConfiguration; // 注入shardingsphere的分库分表配置信息 public UpdateByIdWithSharding(YamlShardingRuleConfiguration yamlShardingRuleConfiguration) { this.yamlShardingRuleConfiguration = yamlShardingRuleConfiguration; } @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { String tableName = tableInfo.getTableName(); // shardingsphere 分库分表配置信息 Map<String, YamlTableRuleConfiguration> tables = yamlShardingRuleConfiguration.getTables(); // 判断当前表是否设置了分表字段 if (tables.containsKey(tableName)) { YamlTableRuleConfiguration tableRuleConfiguration = tables.get(tableName); // 获取分表字段 String shardingColumn = tableRuleConfiguration.getTableStrategy().getStandard().getShardingColumn(); // 构建sql boolean logicDelete = tableInfo.isLogicDelete(); SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID; // 增加分表字段判断 String shardingAdditional = getShardingColumnWhere(tableInfo, shardingColumn); // 是否判断逻辑删除字段 final String additional = optlockVersion() + tableInfo.getLogicDeleteSql(true, false); shardingAdditional = shardingAdditional + additional; String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), getSqlSet(logicDelete, tableInfo, shardingColumn), tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), shardingAdditional); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); return addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource); } else { return super.injectMappedStatement(mapperClass, modelClass, tableInfo); } } /** * where条件增加分表字段 */ private String getShardingColumnWhere(TableInfo tableInfo, String shardingColumn) { StringBuilder shardingWhere = new StringBuilder(); shardingWhere.append(" AND ").append(shardingColumn).append("=#{"); shardingWhere.append(ENTITY_DOT); TableFieldInfo fieldInfo = tableInfo.getFieldList().stream() .filter(f -> f.getColumn().replaceAll(columnDot, StringUtils.EMPTY).equals(shardingColumn)) .findFirst().get(); shardingWhere.append(fieldInfo.getEl()); shardingWhere.append("}"); return shardingWhere.toString(); } /** * set模块去掉分表字段 */ public String getSqlSet(boolean ignoreLogicDelFiled, TableInfo tableInfo, String shardingColumn) { List<TableFieldInfo> fieldList = tableInfo.getFieldList(); // 去掉分表字段的set设置,即不修改分表字段 String rmShardingColumnSet = fieldList.stream() .filter(i -> ignoreLogicDelFiled ? !(tableInfo.isLogicDelete() && i.isLogicDelete()) : true) .filter(i -> !i.getColumn().equals(shardingColumn)) .map(i -> i.getSqlSet(ENTITY_DOT)) .filter(Objects::nonNull).collect(joining(NEWLINE)); return rmShardingColumnSet; } }
3.定义一个sql注入器GyhSqlInjector
,添加UpdateByIdWithSharding
对象
// 需注入到spring容器中 @Component public class GyhSqlInjector extends DefaultSqlInjector { /** * shardingsphere 配置信息 */ @Autowired private YamlShardingRuleConfiguration yamlShardingRuleConfiguration; @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 添加 UpdateByIdWithSharding 对象,并注入分库分表信息 methodList.add(new UpdateByIdWithSharding(yamlShardingRuleConfiguration)); return methodList; } }
4.定义一个基础MapperGyhBaseMapper
,添加新的selectById
方法
/** * 自定义的通用Mapper */ public interface GyhBaseMapper<T> extends BaseMapper<T> { int updateById(@Param(Constants.ENTITY) T entity); }
5.所有参与分表的表,在定义Mapper时继承GyhBaseMapper
,那么在使用他的updateById
方法时,将自动增加分库分表判断,准确命中目标表,减少其他分表查询的资源浪费。
以上是针对mybatisplus
的一些简单改造,希望能为你提供一点点帮助~
作者:京东科技 郭艳红
来源:京东云开发者社区 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
谈谈压测方案的那点事 | 京东物流技术团队
前言 在现阶段大促备战的压测不算是一件新鲜事,已经不存在什么技术瓶颈或者资源问题,每个团队都有很多人能够执行性能测试,在一些团队也已经落地了日常常态化,但压测也没有简单到只在压测平台上设置参数、运行脚本,然后去看压测报告中某个指标是否满足压测目标那么简单,我平时也跟一些同学一起做过性能测试,发现在压测过程中存在一些细节问题,有些同学做但不是很理解,压测方案对于性能测试来说是尤为重要一环,今天把对于压测方案方面的一些理解跟大家一起探讨一下; 性能测试的本质是模拟生产环境的用户,构造用户真实的行为请求,对尽量真实的压测系统施加压力,验证系统性能是否满足业务需要,是否存在性能瓶颈; 从里面可以看出核心的几个点:压测目标、压测场景、压测环境,今天主要从三大块来说 一、压测目标 我们在制定压测方案去说起压测目标的时候,很多同学都直接的考虑到TPS、QPS、TP99这些, 忽略了很重要的一项内容就是压测背景,就是因为什么原因我们要做这次压测,压测背景是我们压测的的方向,如果方向错了就会导致我们费时费力压测完成之后,压测的结论是没有意义的 那么压测背景和压测目标的关系是啥呢? 说一下我们现在常见的几...
- 下一篇
Bytebase 2.11.0 - 支持 OceanBase Oracle 模式
🚀 新功能 支持 OceanBase Oracle 模式。 支持设置 MySQL 在线变更参数。 新增项目数据库查看者的角色。 🎄 改进 支持在项目中直接选择所有用户并为之添加角色。 调整了项目页面的布局。 在 SQL 编辑器中通过悬浮面板展示表和列的详情。 🪦 不再支持 Bytebase 新版本中将不再提供书签功能。我们建议您使用浏览器的书签功能作为替代方案。 🐞 Bug 修复 修复在 Azure DevOps 或 Bitbucket 中重命名文件无法触发在 Bytebase 中工单创建的问题。 🎠 社区 感谢 @bds-congnguyen 提交 fix: update bytebase-sql-review.yml for CICD #8984 📕 安装及升级 参考升级指南。如果从之前版本升级,获取新版本后,重新启动升级即可。
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2全家桶,快速入门学习开发网站教程
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作