经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MyBatis » 查看文章
手把手教你如何扩展(破解)mybatisplus的sql生成
来源:cnblogs  作者:京东云开发者  时间:2023/11/15 9:23:17  对本文有异议

mybatisplus 的常用CRUD方法

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

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

BaseMapper.png

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

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

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

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

扩展常用CRUD方法

新增一个通用sql

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

  1. 定义一个SelectByErp类,继承AbstractMethod类,并实现injectMappedStatement方法

  2. 定义sql方法名、sql模板、实现sql的拼接组装

  1. /**
  2. * 新增一个通用sql
  3. */
  4. public class SelectByErp extends AbstractMethod {
  5. // 需要查询的列名
  6. private final String erpColumn = "erp";
  7. // sql方法名
  8. private final String method = "selectByErp";
  9. // sql模板
  10. private final String sqlTemplate = "SELECT %s FROM %s WHERE %s=#{%s} %s";
  11. @Override
  12. public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
  13. // 获取需要查询的字段名及属性名
  14. TableFieldInfo erpFiled = getErpProperty(tableInfo);
  15. // 拼接组装sql
  16. SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlTemplate,
  17. sqlSelectColumns(tableInfo, false),
  18. tableInfo.getTableName(),
  19. erpFiled.getColumn(), erpFiled.getProperty(),
  20. tableInfo.getLogicDeleteSql(true, false)), Object.class);
  21. return this.addSelectMappedStatementForTable(mapperClass, method, sqlSource, tableInfo);
  22. }
  23. /**
  24. * 查询erp列信息
  25. */
  26. private TableFieldInfo getErpProperty(TableInfo tableInfo) {
  27. List<TableFieldInfo> fieldList = tableInfo.getFieldList();
  28. TableFieldInfo erpField = fieldList.stream().filter(filed -> filed.getColumn().equals(erpColumn)).findFirst().get();
  29. return erpField;
  30. }

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

  1. // 需注入到spring容器中
  2. @Component
  3. public class GyhSqlInjector extends DefaultSqlInjector {
  4. @Override
  5. public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
  6. List<AbstractMethod> methodList = super.getMethodList(mapperClass);
  7. // 增加 SelectByErp对象,程序启动后自动加载
  8. methodList.add(new SelectByErp());
  9. return methodList;
  10. }
  11. }

4.定义一个基础MapperGyhBaseMapper,添加selectByErp方法

  1. /**
  2. * 自定义的通用Mapper
  3. */
  4. public interface GyhBaseMapper<T> extends BaseMapper<T> {
  5. List<T> selectByErp(String erp);
  6. }

5.应用中需要使用该SelectByErp方法的表,都继承GyhBaseMapper,那么这些表将都拥有了selectByErp这个查询方法,程序启动后会自动为这些表生成该sql。

  1. public interface XXXMapper extends GyhBaseMapper<XXXTable>

添加一个mybatisplus已有sql

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

method.png

2.比如我想使用AlwaysUpdateSomeColumnById方法,该方法可以在更新时只更新我需要的字段,不进行全字段更新。添加步骤如下。

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

  1. @Component
  2. public class GyhSqlInjector extends DefaultSqlInjector {
  3. @Override
  4. public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
  5. List<AbstractMethod> methodList = super.getMethodList(mapperClass);
  6. // 添加 AlwaysUpdateSomeColumnById 对象
  7. methodList.add(new AlwaysUpdateSomeColumnById());
  8. return methodList;
  9. }
  10. }

4.定义一个基础Mapper 如GyhBaseMapper,添加alwaysUpdateSomeColumnById方法

  1. /**
  2. * 自定义的通用Mapper
  3. */
  4. public interface GyhBaseMapper<T> extends BaseMapper<T> {
  5. int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
  6. }

5.继承GyhBaseMapper的其他Mapper,将自动拥有alwaysUpdateSomeColumnById方法

  1. /**
  2. * 自定义的通用Mapper
  3. */
  4. public interface GyhBaseMapper<T> extends BaseMapper<T> {
  5. int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
  6. }

6.继承GyhBaseMapper的其他Mapper,将自动拥有alwaysUpdateSomeColumnById方法

编辑一个mybatisplus已有sql

1.如果想编辑一个mybatisplus已有sql,比如分库分表系统,执行updateById操作时,虽然主键Id已确定,但目标表不确定,此时可能导致该sql在多张表上执行,造成资源浪费,并且分库分表字段不可修改,默认的updateById不能用,需要改造。以下以shardingsphere分库分表为例。

2.定义一个UpdateByIdWithSharding类,继承UpdateById

  1. public class UpdateByIdWithSharding extends UpdateById {
  2. private String columnDot = "`";
  3. private YamlShardingRuleConfiguration yamlShardingRuleConfiguration;
  4. // 注入shardingsphere的分库分表配置信息
  5. public UpdateByIdWithSharding(YamlShardingRuleConfiguration yamlShardingRuleConfiguration) {
  6. this.yamlShardingRuleConfiguration = yamlShardingRuleConfiguration;
  7. }
  8. @Override
  9. public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
  10. String tableName = tableInfo.getTableName();
  11. // shardingsphere 分库分表配置信息
  12. Map<String, YamlTableRuleConfiguration> tables = yamlShardingRuleConfiguration.getTables();
  13. // 判断当前表是否设置了分表字段
  14. if (tables.containsKey(tableName)) {
  15. YamlTableRuleConfiguration tableRuleConfiguration = tables.get(tableName);
  16. // 获取分表字段
  17. String shardingColumn = tableRuleConfiguration.getTableStrategy().getStandard().getShardingColumn();
  18. // 构建sql
  19. boolean logicDelete = tableInfo.isLogicDelete();
  20. SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
  21. // 增加分表字段判断
  22. String shardingAdditional = getShardingColumnWhere(tableInfo, shardingColumn);
  23. // 是否判断逻辑删除字段
  24. final String additional = optlockVersion() + tableInfo.getLogicDeleteSql(true, false);
  25. shardingAdditional = shardingAdditional + additional;
  26. String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),
  27. getSqlSet(logicDelete, tableInfo, shardingColumn),
  28. tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(),
  29. shardingAdditional);
  30. SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
  31. return addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);
  32. } else {
  33. return super.injectMappedStatement(mapperClass, modelClass, tableInfo);
  34. }
  35. }
  36. /**
  37. * where条件增加分表字段
  38. */
  39. private String getShardingColumnWhere(TableInfo tableInfo, String shardingColumn) {
  40. StringBuilder shardingWhere = new StringBuilder();
  41. shardingWhere.append(" AND ").append(shardingColumn).append("=#{");
  42. shardingWhere.append(ENTITY_DOT);
  43. TableFieldInfo fieldInfo = tableInfo.getFieldList().stream()
  44. .filter(f -> f.getColumn().replaceAll(columnDot, StringUtils.EMPTY).equals(shardingColumn))
  45. .findFirst().get();
  46. shardingWhere.append(fieldInfo.getEl());
  47. shardingWhere.append("}");
  48. return shardingWhere.toString();
  49. }
  50. /**
  51. * set模块去掉分表字段
  52. */
  53. public String getSqlSet(boolean ignoreLogicDelFiled, TableInfo tableInfo, String shardingColumn) {
  54. List<TableFieldInfo> fieldList = tableInfo.getFieldList();
  55. // 去掉分表字段的set设置,即不修改分表字段
  56. String rmShardingColumnSet = fieldList.stream()
  57. .filter(i -> ignoreLogicDelFiled ? !(tableInfo.isLogicDelete() && i.isLogicDelete()) : true)
  58. .filter(i -> !i.getColumn().equals(shardingColumn))
  59. .map(i -> i.getSqlSet(ENTITY_DOT))
  60. .filter(Objects::nonNull).collect(joining(NEWLINE));
  61. return rmShardingColumnSet;
  62. }
  63. }

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

  1. // 需注入到spring容器中
  2. @Component
  3. public class GyhSqlInjector extends DefaultSqlInjector {
  4. /**
  5. * shardingsphere 配置信息
  6. */
  7. @Autowired
  8. private YamlShardingRuleConfiguration yamlShardingRuleConfiguration;
  9. @Override
  10. public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
  11. List<AbstractMethod> methodList = super.getMethodList(mapperClass);
  12. // 添加 UpdateByIdWithSharding 对象,并注入分库分表信息
  13. methodList.add(new UpdateByIdWithSharding(yamlShardingRuleConfiguration));
  14. return methodList;
  15. }
  16. }

4.定义一个基础MapperGyhBaseMapper,添加新的selectById方法

  1. /**
  2. * 自定义的通用Mapper
  3. */
  4. public interface GyhBaseMapper<T> extends BaseMapper<T> {
  5. int updateById(@Param(Constants.ENTITY) T entity);
  6. }

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


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

作者:京东科技 郭艳红

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

原文链接:https://www.cnblogs.com/Jcloud/p/17823637.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号