前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Mybatis/Mybatis-plus执行动态sql片段工具类

Mybatis/Mybatis-plus执行动态sql片段工具类

作者头像
4xx.me
发布于 2022-09-23 04:50:42
发布于 2022-09-23 04:50:42
1.2K00
代码可运行
举报
运行总次数:0
代码可运行

在开发中可能会遇到需要执行动态sql的场景,比如前端传输sql片段或参数,后端拼接sql语句来执行

参考文章:https://www.codeleading.com/article/90405694877/

先看效果

前端传入sql语句和参数,支持全局变量、mybatis的xml语法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# sql
	select
            rtc.*,
            cu.user_name AS created_by_name,
            uu.user_name AS updated_by_name
        from ram_tmp_conf rtc
         LEFT JOIN ${db_dms}.base_user_info cu ON cu.user_id = rtc.created_by
         LEFT JOIN ${db_dms}.base_user_info uu ON uu.user_id = rtc.updated_by
        <trim prefix="where" prefixOverrides="and | or">
            <if test="tableName != null and tableName != ''">
                AND rtc.table_name like concat('%',#{tableName},'%')
            </if>
        </trim>

后端调用

日志输出

结果返回

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "code": 0,
  "data": {
    "iPage": {
      "countId": "",
      "current": 1,
      "hitCount": false,
      "maxLimit": null,
      "optimizeCountSql": true,
      "orders": [],
      "pages": 1,
      "records": [
        {
          "updatedTime": "2022-08-17 17:31:54",
          "createdByName": "张学胜",
          "updatedBy": "3333",
          "agmtTypeId": "1559835398878855168",
          "isValid": "1",
          "updatedByName": "张学胜",
          "tableName": "TEM_001",
          "agmtTmpAddr": "",
          "agmtTypeName": "协议模板001",
          "createdBy": "3333",
          "agmtTypeRemark": "协议模板001",
          "agmtTypeSql": "SELECT * FROM TEM_001;",
          "createdTime": "2022-08-17 17:31:54",
          "importTmpAddr": ""
        }
      ],
      "searchCount": true,
      "size": 1,
      "total": 1
    },
    "list": [
      {
        "updatedTime": "2022-08-17 17:31:54",
        "createdByName": "张学胜",
        "updatedBy": "3333",
        "agmtTypeId": "1559835398878855168",
        "isValid": "1",
        "updatedByName": "张学胜",
        "tableName": "TEM_001",
        "agmtTmpAddr": "",
        "agmtTypeName": "协议模板001",
        "createdBy": "3333",
        "agmtTypeRemark": "协议模板001",
        "agmtTypeSql": "SELECT * FROM TEM_001;",
        "createdTime": "2022-08-17 17:31:54",
        "importTmpAddr": ""
      }
    ]
  },
  "isImport": false,
  "maxWidth": {},
  "msg": "",
  "success": 1
}

可以看到,没有问题

工具类分享

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.amazonaws.opendistro.elasticsearch.sql.jdbc.shadow.com.amazonaws.util.StringInputStream;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eye.channelflow.core.vo.MsgException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * Mybatis构建sql工具类
 * Created by GMQ on 2022/8/20 14:39
 */
@Component
public class MybatisUtil {

    @Autowired
    SqlSession sqlSession;

    /**
     * 执行sql, 支持mybatis mapper.xml语法
     *
     * @param sql       执行的sql表达式
     * @param parameter 参数
     * @return
     */
    public List<Map<String, Object>> query(String sql, Map<String, Object> parameter) {
        List<Map<String, Object>> result = null;
        try {
            Configuration configuration = sqlSession.getConfiguration();
            StaticLog.info("sql:{}", sql);
            String uuid = IdUtil.fastSimpleUUID();
            StringInputStream inputStream = new StringInputStream("<?xml version=\"1.0\" encoding=\"UTF-8\" ?> <!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" > <mapper> <select id=\"" + uuid + "\" resultType=\"java.util.Map\"> " + sql + " </select> </mapper>");
            XPathParser parser = new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver());
            XNode node = parser.evalNode("/mapper").evalNodes("select").get(0);
            XMLStatementBuilder xmlStatementBuilder = new XMLStatementBuilder(configuration, new MapperBuilderAssistant(configuration, inputStream.toString()), node, null);
            xmlStatementBuilder.parseStatementNode();
            Executor executor = newExecutor(configuration);
            MappedStatement mappedStatement = configuration.getMappedStatement(uuid);

            StaticLog.info("==> Preparing: {}", mappedStatement.getBoundSql(parameter).getSql());
            StaticLog.info("==> Parameters: {}", mappedStatement.getBoundSql(parameter).getParameterObject());
            result = executor.query(mappedStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
        } catch (Exception e) {
            StaticLog.error("sql执行错误: ", e.getMessage());
            e.printStackTrace();
            throw new MsgException("sql执行错误");
        }
        return result;
    }

    /**
     * 分页查询
     *
     * @param page
     * @param sql
     * @param parameter
     * @return com.baomidou.mybatisplus.core.metadata.IPage<java.util.Map>
     * @throws
     * @author GMQ
     * @date 2022/8/21 11:59
     **/
    public IPage<Map> queryPage(Page page, String sql, Map<String, Object> parameter) {
        IPage<Map> iPage = page;
        try {
            Configuration configuration = sqlSession.getConfiguration();
            String uuid = IdUtil.fastSimpleUUID();
            String countSql = StrUtil.format("select count(*) from ( {} ) count_select", sql);
            StaticLog.info("countSql:{}", countSql);
            StringInputStream inputStream = new StringInputStream("<?xml version=\"1.0\" encoding=\"UTF-8\" ?> <!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" > <mapper> <select id=\"" + uuid + "\" resultType=\"java.lang.Integer\"> " + countSql + " </select> </mapper>");
            XPathParser parser = new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver());
            XNode node = parser.evalNode("/mapper").evalNodes("select").get(0);
            XMLStatementBuilder xmlStatementBuilder = new XMLStatementBuilder(configuration, new MapperBuilderAssistant(configuration, inputStream.toString()), node, null);
            xmlStatementBuilder.parseStatementNode();
            Executor executor = newExecutor(configuration);
            MappedStatement mappedStatement = configuration.getMappedStatement(uuid);

            StaticLog.info("==> Preparing: {}", mappedStatement.getBoundSql(parameter).getSql());
            StaticLog.info("==> Parameters: {}", mappedStatement.getBoundSql(parameter).getParameterObject());
            Object result = executor.query(mappedStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER).get(0);
            page.setTotal(result == null ? 0L : Long.parseLong(result.toString()));
            if (page.getTotal() > 0) {
                page.setRecords(query(StrUtil.format("{} limit {},{}", sql, page.offset(), page.getSize()), parameter));
            }
        } catch (Exception e) {
            StaticLog.error("sql执行错误: ", e.getMessage());
            throw new MsgException("sql执行错误");
        }
        return iPage;
    }


    private Executor newExecutor(Configuration configuration) {
        final Environment environment = configuration.getEnvironment();
        if (environment == null) {
            throw new ExecutorException("ResultLoader could not load lazily.  Environment was not configured.");
        }
        final DataSource ds = environment.getDataSource();
        if (ds == null) {
            throw new ExecutorException("ResultLoader could not load lazily.  DataSource was not configured.");
        }
        final TransactionFactory transactionFactory = environment.getTransactionFactory();
        final Transaction tx = transactionFactory.newTransaction(ds, null, false);
        return configuration.newExecutor(tx, ExecutorType.SIMPLE);
    }

}

依赖hutool工具类,可自己实现修改

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
源码学习之MyBatis的底层查询原理
Tech      导读 本文通过MyBatis一个低版本的bug(3.4.5之前的版本)入手,分析MyBatis的一次完整的查询流程,从配置文件的解析到一个查询的完整执行过程详细解读MyBatis的一次查询流程,通过本文可以详细了解MyBatis的一次查询过程。在平时的代码编写中,发现了MyBatis一个低版本的bug(3.4.5之前的版本),由于现在很多工程中的版本都是低于3.4.5的,因此在这里用一个简单的例子复现问题,并且从源码角度分析MyBatis一次查询的流程,让大家了解MyBatis的查询
京东技术
2022/06/24
5220
源码学习之MyBatis的底层查询原理
MyBatis 源代码阅读笔记 1 基于XML配置的代码编写 mybatis-config.xml
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
一个会写诗的程序员
2019/07/25
1.2K0
MyBatis核心流程源码分析(上)
3.创建实体类User以及UserDAO和对应的xml文件,以及mybats主配置文件
全干程序员demo
2024/01/17
2190
MyBatis核心流程源码分析(上)
Mybatis源码解析一(SqlSessionFactory和SqlSession的获取)
SqlSessionFactory是MyBatis的关键对象, 它是个单个数据库映射关系经过编译后的内存镜像; SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得; SqlSessionFactoryBuilder从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例; 每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心, 同时SqlSessionFactory也是线程安全的, SqlSessionFactory一旦被创建, 应该在应用执行期间都存在; 在应用运行期间不要重复创建多次, 建议使用单例模式SqlSessionFactory是创建SqlSession的工厂;
全栈程序员站长
2022/09/02
1K0
Mybatis源码分析
variables:用来存放 properties 节点中解析出来的 Properties 数据。
用户7353950
2022/06/23
4830
Mybatis源码分析
Mybatis利用拦截器做统一分页
查询传递Page参数,或者传递继承Page的对象参数。拦截器查询记录之后,通过改造查询sql获取总记录数。赋值Page对象,返回。
WindWant
2020/09/11
6800
Mybatis 源码分析(二)之 Mybatis 操作数据库的流程
Mybatis系列: Mybatis 基础介绍与逆向工程的构建 :https://www.jianshu.com/p/1c18db4d7a38 Mybatis 源码分析(一)之 Mybatis 的Executor的初始化:https://www.jianshu.com/p/c7425c841337 Mybatis 源码分析(二)之 Mybatis 操作数据库的流程 :https://www.jianshu.com/p/11d354ec3612 Mybatis 源码分析(三)之 Mybatis 的一级缓存和二级缓存 :https://www.jianshu.com/p/5515640d14fe
zoro
2019/04/11
1.1K0
mybatis拦截器详解_短信拦截器
  拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor。这个时候如果你觉得这几种实现对于Executor接口的query方法都不能满足你的要求,那怎么办呢?是要去改源码吗?当然不。我们可以建立一个Mybatis拦截器用于拦截Executor接口的query方法,在拦截之后实现自己的query方法逻辑,之后可以选择是否继续执行原来的query方法。
全栈程序员站长
2022/09/30
1.7K0
MyBatis3-实现MyBatis分页
此文章中的例子是沿用上一篇文章http://www.cnblogs.com/EasonJim/p/7055499.html的Spring MVC集成的例子改装的。
林老师带你学编程
2019/05/25
1.4K0
MyBatis核心流程源码分析(下)​
上面说了mybatis的核心对象,我们使用mybatis操作数据库使用到的仅仅只是SqlSession对象,下面我们看看SqlSession如何使用核心对象帮助我们完成这一系列操作.
全干程序员demo
2024/01/19
2570
MyBatis核心流程源码分析(下)​
Mybatis 源码分析(一)之 Mybatis 的Executor的初始化
Mybatis系列: Mybatis 基础介绍与逆向工程的构建 :https://www.jianshu.com/p/1c18db4d7a38 Mybatis 源码分析(一)之 Mybatis 的Executor的初始化:https://www.jianshu.com/p/c7425c841337 Mybatis 源码分析(二)之 Mybatis 操作数据库的流程 :https://www.jianshu.com/p/11d354ec3612 Mybatis 源码分析(三)之 Mybatis 的一级缓存和二级缓存 :https://www.jianshu.com/p/5515640d14fe
zoro
2019/04/11
3910
Mybatis 源码分析(一)之 Mybatis 的Executor的初始化
Mybatis分页拦截器
5.注意,参数都要封装到对象里,不能用string,int等基本类型,因为在拦截器中获取参数时用的是getter,基本类型数据没有getter和setter
IT云清
2019/01/22
2.2K0
Mybatis 源码分析
框架是对原来操作的扩展封装,接下来我们来看下 Mybatis 是如何将几行代码扩展成一个框架的。
啵啵肠
2023/11/20
1830
Mybatis源码解析-执行流程(旧)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
Java微观世界
2025/01/20
1180
Mybatis源码解析-执行流程(旧)
MyBatis源码阅读(八) --- Executor执行器
Executor 是一个接口,包含更新,查询,事务等一系列方法。在前面分析SqlSession创建过程的时候,我们知道每个SqlSession对象都会有一个Executor对象,SqlSession的操作都会交由Executor执行器执行。
终有救赎
2024/01/30
4320
MyBatis源码阅读(八) --- Executor执行器
怒肝一夜 | Mybatis源码深度解析
前面已经发过Mybatis源码解析的文章了,本文是对前面文章进行精简以及部分调整优化,总结出来的一篇万字Mybatis源码分析。
田维常
2021/01/13
6.6K0
怒肝一夜 | Mybatis源码深度解析
Mybatis 分页
拦截StatementHandler的prepare方法 具体类PreparePaginationInterceptor 里面SQLHelper.generatePageSql(sql, page, DIALECT);
week
2019/02/22
8970
MyBatis 源码
MyBatis 工作流程:应用程序首先加载mybatis-config.xml 配置文件,并根据配置文件的内容创建 SqlSessionFactory 对象;然后,通过 SqlSessionFactory 对象创建 SqlSession 对象,SqlSession 接口中定义了执行 SQL 语句所需要的各种方法。之后,通过 SqlSession 对象执行映射配置文件中定义的 SQL 语句,完成相应的数据操作。最后通过 SqlSession 对象提交事务,关闭 SqlSession 对象,整个过程具体实现如下:就按照下面的流程进行源码分析
Java架构师必看
2021/05/14
3290
MyBatis 源码
MyBatis系列之分页插件及问题
无论是C端产品页面,还是后台系统页面,不可能一次性将全部数据加载出来。后台系统一般都是PC端登录,用Table组件(如Ant Design Table)渲染展示数据,可点击列表的下一页(或指定某一页)查看数据。C端产品如App,在下滑时可查看更多数据,看起来像是一次性加载数据,实际上也是分批请求后台系统获取数据。而这,就是分页功能。
johnny666
2024/09/17
1700
MyBatis入门到源码分析 | 【Mybatis加载核心配置文件流程】
resources目录下创建:mybatis-config.xml,并写入以下内容:
青山师
2023/05/05
3010
相关推荐
源码学习之MyBatis的底层查询原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验