手把手教你如何扩展(激活成功教程)mybatisplus的sql生成

手把手教你如何扩展(激活成功教程)mybatisplus的sql生成mybatisplus 的常用 CRUD 方法众所周知 mybatisplus 提供了强大的代码生成能力 他默认生成的常用的 CRUD 方法 例如插入 更新 删除 查询等 的定义 能够帮助我们节省很多体力劳动

欢迎大家来到IT世界,在知识的湖畔探索吧!

mybatisplus 的常用 CRUD 方法

众所周知,mybatisplus 提供了强大的代码生成能力,他默认生成的常用的 CRUD 方法(例如插入、更新、删除、查询等)的定义,能够帮助我们节省很多体力劳动。

他的 BaseMapper 中定义了这些常用的 CRUD 方法,我们在使用时,继承这个 BaseMapper 类就默认拥有了这些能力。

手把手教你如何扩展(激活成功教程)mybatisplus的sql生成



欢迎大家来到IT世界,在知识的湖畔探索吧!

如果我们的业务中,需要类似的通用 Sql 时,该如何实现呢?

是每个 Mapper 中都定义一遍类似的 Sql 吗?

显然这是最笨的一种方法。

此时我们可以借助 mybatisplus 这个成熟框架,来实现我们想要的通用 Sql。

扩展常用 CRUD 方法

新增一个通用 sql

比如有一个这样的需求,项目中所有表或某一些表,都要执行一个类似的查询,如 `SelectByErp`,那么可以这样实现。(这是一个最简单的 sql 实现,使用时可以根据业务需求实现更为复杂的 sql:比如多租户系统自动增加租户 id 参数、分库分表系统增加分库分表字段条件判断)

  1. 定义一个 SelectByErp 类,继承 AbstractMethod 类,并实现 injectMappedStatement 方法
  2. 定义 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; }

欢迎大家来到IT世界,在知识的湖畔探索吧!

3. 定义一个 sql 注入器 GyhSqlInjector,添加 SelectByErp 对象

欢迎大家来到IT世界,在知识的湖畔探索吧!// 需注入到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。

欢迎大家来到IT世界,在知识的湖畔探索吧!public interface XXXMapper extends GyhBaseMapper<XXXTable> 

添加一个 mybatisplus 已有 sql

1.mybatisplus 常用 CRUD 方法如最上图,这些方法已经默认会自动生成,但 mybatisplus 其实提供了更多的方法,如下图,只要我们在启动时添加进去,就可以使用了。

手把手教你如何扩展(激活成功教程)mybatisplus的sql生成

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 方法

欢迎大家来到IT世界,在知识的湖畔探索吧!/ * 自定义的通用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

欢迎大家来到IT世界,在知识的湖畔探索吧!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 方法

欢迎大家来到IT世界,在知识的湖畔探索吧!/ * 自定义的通用Mapper */ public interface GyhBaseMapper<T> extends BaseMapper<T> { int updateById(@Param(Constants.ENTITY) T entity); } 

5. 所有参与分表的表,在定义 Mapper 时继承 GyhBaseMapper,那么在使用他的 updateById 方法时,将自动增加分库分表判断,准确命中目标表,减少其他分表查询的资源浪费。


以上是针对 mybatisplus 的一些简单改造,希望能为你提供一点点帮助~

作者:京东科技 郭艳红

来源:京东云开发者社区 转载请注明来源

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/104486.html

(0)
上一篇 1小时前
下一篇 1小时前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信