手把手教你如何扩展(破解)mybatisplus的sql生成

这篇具有很好参考价值的文章主要介绍了手把手教你如何扩展(破解)mybatisplus的sql生成。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

mybatisplus 的常用CRUD方法

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

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

如果我们的业务中,需要类似的通用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;
    }

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的一些简单改造,希望能为你提供一点点帮助~

作者:京东科技 郭艳红

来源:京东云开发者社区 转载请注明来源文章来源地址https://www.toymoban.com/news/detail-750095.html

到了这里,关于手把手教你如何扩展(破解)mybatisplus的sql生成的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 数据库:如何安装SQL,手把手教你

    数据库:如何安装SQL,手把手教你

    我们只选择两个: SQLEXPR_x64_CHS.exe SQLManagementStudio_x64_CHS.exe 如果你是32位系统就选择x86的(9102年了,应该都是64位的了吧)选中后下载到你经常保存文件的地方即可(这个地方并不是sql要安装的地方)。 全部下载后如图所示 正式安装 先安装SQL,再安装 SQL Management Studio 双击

    2024年01月16日
    浏览(56)
  • [R语言]手把手教你如何绘图(万字)

    [R语言]手把手教你如何绘图(万字)

    目录 概况 常用高级图形 条形图 csv文件导入 csv文件导出 R语言sep函数 seq函数 with函数 直方图和密度估计图 盒型图 boxplot() 正态QQ图 散点图 pairs()散点矩阵图 曲线图 curve() 三维图 动态三维图 低级图形函数 abline() lines() legand()增加图例 axis()坐标轴 text()给图内区域添加文字 loc

    2024年02月04日
    浏览(7)
  • 手把手教你如何使用Fiddler抓包工具

    手把手教你如何使用Fiddler抓包工具

    什么是 Fiddler? Fiddler 是一个 HTTP 协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的 HTTP 通讯。Fiddler 提供了电脑端、移动端的抓包、包括 http 协议和 https 协议都可以捕获到报文并进行分析;可以设置断点调试、截取报文进行请求替换和数据篡改,也可以进行

    2024年02月07日
    浏览(36)
  • .net8系列-04图文并茂手把手教你配置Swagger支持token以及实现Swagger扩展,Swagger代码单独抽离

    .net8系列-04图文并茂手把手教你配置Swagger支持token以及实现Swagger扩展,Swagger代码单独抽离

    接上篇文章,我们当前已完成如下内容: 创建应用成功 创建接口成功 配置Swagger实现接口注释和版本控制 本文章主要内容为: 配置Swagger支持token传值测试接口 添加如下代码 文件目录:xiaojinWebApplicationxiaojinWebApplicationProgram.cs 打开接口测试页面 配置Token 观察页面 我们发现

    2024年04月27日
    浏览(8)
  • Java基础--手把手教你如何从键盘录入信息

    Java基础--手把手教你如何从键盘录入信息

    从键盘录入信息 Scanner 有扫描仪的意思,sc是自己取的名字(有的人喜欢用input), new Scanner 是创建一个Scanner对象, System.in 代表电脑的键盘。 即,扫描电脑的键盘。 将第一步写完,我们在编译器里面看到, Scanner 标红了,报错了! ❓ 为啥报错呢? 我们要使用 Scanner ,需要

    2024年02月11日
    浏览(10)
  • pr如何导出mp4格式视频?手把手教你

    pr如何导出mp4格式视频?手把手教你

    PR是一款强大的视频编辑软件,广泛应用于电影、电视制作以及各类创意视频项目。在完成编辑后,将项目导出为MP4格式视频是常见的需求,因为MP4是一种通用且高度兼容的视频格式,适用于多个平台和设备。pr如何导出mp4格式视频?在本文中,我们将深入讨论如何在PR中导出

    2024年02月21日
    浏览(8)
  • 手把手教你如何正确永久使用Microsoft Office365?

    手把手教你如何正确永久使用Microsoft Office365?

    office2019和office 365有什么区别的呢?为什么越来越多的人更加钟爱office365。简单来说office 2019的零售版本属于一次售出永久使用,价格上比较贵,而且功能上也不会再有更新。而office 365是一种基于云的订阅服务,我们花钱买的是一定时期的服务,在使用期间我们可以获得offi

    2024年02月07日
    浏览(35)
  • Joker零安全手把手教你如何搭建vulfocus靶场

    Joker零安全手把手教你如何搭建vulfocus靶场

    vulfocus是一个漏洞集成平台,将漏洞环境docker镜像放入即可,开箱即用,简直就是居家打靶的必备良药啊😁; 一键漏洞环境启动方便简单; 自带 flag 功能且每次启动 flag 都会自动更新,明确漏洞是否利用成功; 带有计分功能也可适用于相关安全人员能力的考核; 兼容 Vulh

    2024年02月06日
    浏览(12)
  • 【VScode】手把手教你如何搭建C/C++开发环境

    【VScode】手把手教你如何搭建C/C++开发环境

    目录 1.VScode是什么 2.VScode的下载和安装  安装中文插件 3.VScode配置C/C++开发环境 3.1 下载MinGW-w64 编译器套件 3.2 配置MinGW-w64  3.3 安装C/C++插件 4.在VScode上编写C语言代码并编译成功 4.1打开文件夹 4.2 新建C语言文件,编写C语言代码 4.3设置C/C++编译的选项 4.4 创建执行任务:tasks.

    2023年04月21日
    浏览(12)
  • 手把手教你如何使用Unity搭建简易图片服务器

    手把手教你如何使用Unity搭建简易图片服务器

    目录 引言 服务器 WAMP简介 WAMP的配置与使用 主要的WAMP集成环境有: 正文 1、外部工具素材准备 首先下载并安装 WAMP  图片路径设置 2、创建 Unity 工程 将图片加载到 Unity 项目中: 代码块 运行效果如下: 网络游戏中,服务器的搭建尤为重要,无论是授权服务器,还是非授权服务

    2024年02月02日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包