当前位置: 首页 > news >正文

mybatis多条件in查询拓展

背景

最近碰上有个业务,查询的sql如下:

select * from table where (sku_id,batch_no) in ((#{skuId},#{batchNo}),...); 

本来也没什么,很简单常见的一种sql。问题是我们使用的是mybatis-plus,然后写的时候又没有考虑到后面的查询条件,这里用的是mybatis-plus lambda的方式。

LambdaQueryChainWrapper<Table> query = tableService.lambdaQuery();  
query.eq(Table::getId, param.getId()); 

但是mysql-plus并没有支持这种sql的形式,要么用apply方法自定义拼接sql,要么不采用lambda方式,将语句写成 xml 形式。

不过,第一种方式感觉很 low,一大段 java 代码里插入一段sql字符串,看上去就很别扭,因为有点代码洁癖,只能果断放弃。

第二种改动又太大,前面那么多查询条件,又要全部移入xml里面,同时,本来已经通过测试的筛选条件,又要重新来一遍,太懒,实在干不动了。

想想这么常见的场景,网上理应有现成的解决方案。但不知道是搜索关键字不对还是确实没有,搜了半天没搜出来。

最后无奈,只能尝试自己扩展一下。

代码

import com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import io.vavr.Tuple;
import org.springframework.util.Assert;import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;import static com.baomidou.mybatisplus.core.enums.SqlKeyword.IN;
import static java.util.stream.Collectors.joining;public class CombinationLambdaQueryChainWrapper<T> extends AbstractLambdaWrapper<T, CombinationLambdaQueryChainWrapper<T>> {/*** 查询字段*/private String sqlSelect;public CombinationLambdaQueryChainWrapper() {this(null);}public CombinationLambdaQueryChainWrapper(T entity) {this.entity = entity;this.initEntityClass();this.initNeed();}CombinationLambdaQueryChainWrapper(T entity, Class<T> entityClass, String sqlSelect, AtomicInteger paramNameSeq, Map<String, Object> paramNameValuePairs,MergeSegments mergeSegments) {this.entity = entity;this.paramNameSeq = paramNameSeq;this.paramNameValuePairs = paramNameValuePairs;this.expression = mergeSegments;this.sqlSelect = sqlSelect;this.entityClass = entityClass;}/*** <p>* SELECT 部分 SQL 设置* </p>** @param columns 查询字段*/@SafeVarargspublic final CombinationLambdaQueryChainWrapper<T> select(SFunction<T, ?>... columns) {if (ArrayUtils.isNotEmpty(columns)) {this.sqlSelect = this.columnsToString(columns);}return typedThis;}public CombinationLambdaQueryChainWrapper<T> select(Predicate<TableFieldInfo> predicate) {return select(entityClass, predicate);}/*** <p>* 过滤查询的字段信息(主键除外!)* </p>* <p>* 例1: 只要 java 字段名以 "test" 开头的              -> select(i -> i.getProperty().startsWith("test"))* 例2: 只要 java 字段属性是 CharSequence 类型的       -> select(TableFieldInfo::isCharSequence)* 例3: 只要 java 字段没有填充策略的                   -> select(i -> i.getFieldFill == FieldFill.DEFAULT)* 例4: 要全部字段                                   -> select(i -> true)* 例5: 只要主键字段                                 -> select(i -> false)* </p>** @param predicate 过滤方式* @return this*/public CombinationLambdaQueryChainWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {this.entityClass = entityClass;this.sqlSelect = TableInfoHelper.getTableInfo(getCheckEntityClass()).chooseSelect(predicate);return typedThis;}@Overridepublic String getSqlSelect() {return sqlSelect;}/*** <p>* 用于生成嵌套 sql* 故 sqlSelect 不向下传递* </p>*/@Overrideprotected CombinationLambdaQueryChainWrapper<T> instance(AtomicInteger paramNameSeq, Map<String, Object> paramNameValuePairs) {return new CombinationLambdaQueryChainWrapper<>(entity, entityClass, null, paramNameSeq, paramNameValuePairs, new MergeSegments());}/*** 组合IN查询* 此处引入元祖,需使用io.vavr包**/public CombinationLambdaQueryChainWrapper<T> combinationIn(boolean condition, List<Tuple> list, SFunction<T, ?>... columns) {Assert.isTrue(columns.length == list.get(0).arity(), "请检查组合IN查询参数长度");return doIt(condition,() -> StringPool.LEFT_BRACKET + columnsToString(columns) + StringPool.RIGHT_BRACKET,IN,inExpressionOfParam(list));}private ISqlSegment inExpressionOfParam(List<Tuple> list) {if (list.size() > 1000) {throw new RuntimeException("组合查询禁止超过1000条");}List<String> result = list.stream().map(m -> StringPool.LEFT_BRACKET + m.toSeq().asJava().stream().map(n -> n instanceof String ? StringPool.SINGLE_QUOTE + n + StringPool.SINGLE_QUOTE : String.valueOf(n)).collect(Collectors.joining(StringPool.COMMA)) + StringPool.RIGHT_BRACKET).collect(Collectors.toList());return () -> result.stream().collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));}}

使用示例

        productRelService.list(new CombinationLambdaQueryChainWrapper<ProductRel>().select(ProductRel::getLevelId).eq(ProductRel::getLevelId, "GBZ0555A0002").combinationIn(true, Arrays.asList(Tuple.of("91cf1c0f3b0bc46e0238dc33717dc88e", "GBZ0555A0002")), ProductRel::getProductUuid, ProductRel::getLevelId));productRelService.list(new CombinationLambdaQueryChainWrapper<ProductRel>().combinationIn(true, Arrays.asList(Tuple.of(1L, "GBZ0555A0002")), ProductRel::getId, ProductRel::getLevelId));

相关文章:

mybatis多条件in查询拓展

背景 最近碰上有个业务&#xff0c;查询的sql如下&#xff1a; select * from table where (sku_id,batch_no) in ((#{skuId},#{batchNo}),...); 本来也没什么&#xff0c;很简单常见的一种sql。问题是我们使用的是mybatis-plus&#xff0c;然后写的时候又没有考虑到后面的查…...

<Rust><iced>基于rust使用iced构建GUI实例:一个CRC16校验码生成工具

前言 本专栏是Rust实例应用。 环境配置 平台:windows 软件:vscode 语言:rust 库:iced、iced_aw 概述 本文是专栏第五篇实例,是一个CRC16校验码转换程序。 本篇内容: 1、CRC16校验码生成 代码介绍 本文的crc16校验码生成工具,主要设计两个方面,一个是crc16 modbus…...

动态规划与0/1背包问题:深入解析

目录 一、动态规划简介 二、0/1背包问题概述 三、动态规划解决0/1背包问题 1. 定义子问题 2. 确定状态 3. 初始条件和边界情况 4. 计算最终结果 5. 代码实现 6. 空间优化 四、例题讲解 例题1&#xff1a;基础例题 例题2&#xff1a;路径恢复 例题3&#xff1a;扩展…...

Python爬虫:下载人生格言

Python爬虫:下载人生格言 爬取网页 将这些格言下载存储到本地 代码: import requests #导入requests库&#xff0c;用于提取网页 from lxml import etree#导入lxml库&#xff0c;用于Xpath数据解析#请求头 header{ user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) A…...

使用注意力机制的seq2seq

一、背景 1、机器翻译中&#xff0c;每个生成的词可能相关于源句子中不同的词&#xff0c;但是之前用的是最后一个RNN层出来的context。 2、加入注意力 &#xff08;1&#xff09;假设输入序列中有&#x1d447;个词元&#xff0c; 解码时间步&#x1d461;′的上下文变量是…...

我们的前端开发逆天了!1 小时搞定了新网站,还跟我说 “不要钱”

大家好&#xff0c;我是程序员鱼皮。前段时间我们上线了一个新软件 剪切助手 &#xff0c;并且针对该项目做了一个官网&#xff1a; 很多同学表示官网很好看&#xff0c;还好奇是怎么做的&#xff0c;其实这个网站的背后还有个有趣的小故事。。。 鱼皮&#xff1a;我们要做个官…...

.NET 相关概念

.NET 和 .NET SDK .NET 介绍 .NET 是一个由 Microsoft 开发和维护的广泛用于构建各种类型应用程序的开发框架。它是一个跨平台、跨语言的开发平台&#xff0c;提供了丰富的类库、API和开发工具&#xff0c;支持开发者使用多种编程语言&#xff08;如C#、VB.NET、F#等&#xf…...

Kubernetes 从集群中移除一个节点(Node)

目录 1. 移除工作节点(Worker Node)1.1 确定工作节点名称1.2 驱逐工作节点上的Pod1.3 删除工作节点1.4 重置该工作节点 2. 移除控制平面节点(Control Plane Node)2.1 确定控制平面节点名称2.2 驱逐控制平面节点上的Pod2.3 更新 etcd 集群2.4 从集群中删除控制平面节点2.5 重置移…...

高德地图离线版 使用高德地图api的方法

高德离线包我已经存至Gitee&#xff08;自行下载即可&#xff09;&#xff1a;高德地图离线解决方案: 高德地图离线解决方案 然因为高德地图的瓦片地图太大&#xff0c;所以要让后端部署下 前端直接调用 如果本地 直接找到瓦片图路径就可以 initMap () {const base_url "…...

springboot 集成私有化Ollama大模型开源框架,搭建AI智能平台

Ollama是一个用于大数据和机器学习的平台&#xff0c;它可以帮助企业进行数据处理、分析和决策制定。 &#xff11;、在Spring Boot项目pom.xml中添加Ollama客户端库依赖 <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-a…...

6.key的层级结构

redis的key允许多个单词形成层级结构&#xff0c;多个单词之间用:隔开&#xff0c;格式如下&#xff1a; 项目名:业务名:类型:id 这个格式并非固定的&#xff0c;可以根据自己的需求来删除或添加词条。 例如&#xff1a; taobao:user:1 taobao:product:1 如果value是一个java对…...

LogonTracer图形化事件分析工具

LogonTracer这款工具是基于Python编写的&#xff0c;并使用Neo4j作为其数据库&#xff08;Neo4j多用于图形数据库&#xff09;&#xff0c;是一款用于分析Windows安全事件登录日志的可视化工具。它会将登录相关事件中的主机名&#xff08;或IP地址&#xff09;和帐户名称关联起…...

【云原生】Prometheus监控Docker指标并接入Grafana

目录 一、前言 二、docker监控概述 2.1 docker常用监控指标 2.2 docker常用监控工具 三、CAdvisor概述 3.1 CAdvisor是什么 3.2 CAdvisor功能特点 3.3 CAdvisor使用场景 四、CAdvisor对接Prometheus与Grafana 4.1 环境准备 4.2 docker部署CAdvisor 4.2.2 docker部署…...

搭建日志系统ELK(二)

搭建日志系统ELK(二) 架构设计 在搭建以ELK为核心的日志系统时&#xff0c;Logstash作为日志采集的核心组件&#xff0c;负责将各个服务的日志数据采集、清洗、过滤。然而缺点也很明显&#xff1a; 占用较多的服务器资源。配置复杂&#xff0c;学习曲线陡峭。处理大数据量时…...

常用排序算法的实现与介绍

常用排序算法的实现与介绍 在计算机科学中&#xff0c;排序算法是非常基础且重要的一类算法。本文将通过C语言代码实现&#xff0c;介绍几种常见的排序算法&#xff0c;包括冒泡排序、选择排序、插入排序和快速排序。以下是这些排序算法的具体实现和简要介绍。 1. 冒泡排序&am…...

仓颉语言 -- 宏

使用新版本 &#xff08;2024-07-19 16:10发布的&#xff09; 1、宏的简介 宏可以理解为一种特殊的函数。一般的函数在输入的值上进行计算&#xff0c;然后输出一个新的值&#xff0c;而宏的输入和输出都是程序本身。在输入一段程序&#xff08;或程序片段&#xff0c;例如表达…...

Nginx代理minIO图片路径实现公网图片访问

1、网络部署情况 VUE前端项目Nginx部署在公司内网&#xff0c;端口7790 后台接口项目部署在公司内网&#xff0c;端口7022 minIO服务部署在公司内网&#xff0c;端口9000 公网IP设备将80端口映射到7790端口&#xff08;具体映射方式不详&#xff09;&#xff0c;实现通过互…...

从零开始掌握tcpdump:参数详解

Linux tcpdump命令详解 1. 语法 tcpdump [-adeflnnNOpqStvxX] [-c <数据包数目>] [-dd] [-ddd] [-F <表达文件>] [-i <网络界面>] [-r <数据包文件>] [-s <数据包大小>] [-tt] [-T <数据包类型>] [-vv] [-w <数据包文件>] [输出数…...

漏洞挖掘 | edusrc记一次某中学小程序渗透测试

一、搜集渗透目标 现在的EDU挖web端的上分效率远不如小程序&#xff0c;因此这篇文章浅浅记录一次小程序的挖掘吧。如果各位大牛想要快速出洞&#xff0c;不妨跳过大学&#xff0c;学院等小程序&#xff0c;而重点关注小学、中学、幼儿园等&#xff0c;这些小程序的出洞率还是…...

vulhub:nginx解析漏洞CVE-2013-4547

此漏洞为文件名逻辑漏洞&#xff0c;该漏洞在上传图片时&#xff0c;修改其16进制编码可使其绕过策略&#xff0c;导致解析为 php。当Nginx 得到一个用户请求时&#xff0c;首先对 url 进行解析&#xff0c;进行正则匹配&#xff0c;如果匹配到以.php后缀结尾的文件名&#xff…...

备战秋招:2024游戏开发入行与跳槽面试详解

注意&#xff1a;以下为本次分享概要&#xff0c;视频版内容更全面深入&#xff0c;详见文末 1.游戏开发领域秋招准备与面试技巧 本次分享由优梦创客机构的创始人雷蒙德主讲&#xff0c;专注于2024年秋招期间游戏开发领域的入行与跳槽面试准备。本次分享重点在于提供面试技巧…...

红外热成像手持终端:从建筑检测到野外搜救的全方位应用

红外热成像手持终端&#xff0c;凭借其独特的红外探测与夜视功能&#xff0c;广泛应用于多个关键领域。无论是军事侦察、消防救援中的夜间作业&#xff0c;还是电力巡检、野生动物观察等多样场景&#xff0c;其精准的红外热成像技术均能提供至关重要的实时数据&#xff0c;助力…...

day07 项目启动以及git

spring框架 spring 负责整合各种框架&#xff0c;把new对象的部分交给spring去做&#xff0c;对象new不出来&#xff0c;项目就启动不起来&#xff0c;这样可以有效保证所需要的对象都在容器中存在&#xff0c;后续的部分都可以顺利执行控制反转&#xff1a;业务对象创建依赖资…...

学会网络安全:开启广阔职业与责任之旅

在数字化时代&#xff0c;网络安全已成为社会经济发展的重要基石。随着互联网的普及和技术的飞速发展&#xff0c;网络安全威胁日益复杂多变&#xff0c;对国家安全、社会稳定以及个人隐私构成了严峻挑战。因此&#xff0c;掌握网络安全技能不仅意味着拥有了一项高价值的职业技…...

UE5 镜头

只狼镜头 Spring Arm 中 开启 Use Pawn Control Rotation&#xff1a;让镜头跟着鼠标移动BP_Character(Self) 中关闭 Use Controller Rotation Yaw&#xff1a;不要让人物和鼠标移动Character Movement 的 Rotation Setting 中 关闭 Use Controller Desired Rotation&#xff…...

SpringBoot如何实现简单的跨域配置

在SpringBoot中实现简单的跨域配置&#xff0c;主要通过全局CORS配置来完成。这通常涉及到实现WebMvcConfigurer接口并覆盖addCorsMappings方法。以下是一个简单的示例&#xff0c;展示了如何在SpringBoot应用中配置CORS策略以允许跨域请求。 首先&#xff0c;需要创建一个配置…...

vue列表进入详情页实现上一篇下一篇功能

概述&#xff1a;需求就是需要可以看列表&#xff0c;然后点击列表的右侧详情看详情&#xff0c;通过详情来实现新增上一份&#xff0c;下一份按钮来实现直接看之后的详情。 网上的解决方法有很多 1.后台获取将全量的id&#xff0c;前台再去直接取下一个id方式。&#xff08;…...

kalman的python实现

前面的kalman都是matlab的&#xff0c;这里在理解的基础上&#xff0c;尝试使用python实现&#xff0c;力求理解更多的内涵。 需要的包 import numpy as np import matplotlib.pyplot as plt 代码 KF algorith demo by Leo 2020.01.06 ZJG CAMPUS,ZJU import numpy as np…...

查找算法:线性查找,golang实现

目录 前言 线性查找 代码示例 1. 算法包 2. 线性查找代码 3. 模拟程序 4. 运行程序 循环次数 假如目标值正好在数组中的第一位 假如目标值正好在数组中的第五位 假如目标值正好在数组中的最后一位 假如目标值不在数组中 线性查找的思想 1. 顺序遍历 2. 比较 3.…...

【图像识别】十大数据集合集!

本文将为您介绍10个经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 1 DanishFungi2020 发布方&#xff1a; Google 发布时间&#xff1a; 2021 简介&#xff1a; 补充材料&#xff1a;丹麦真菌 2020 - 不仅仅是另一个图像识别数据集为了支持细粒度植…...

佛山商业网站建设/nba最新消息交易情况

遇到问题报错如下&#xff1a; 调试了好多遍&#xff0c;始终不行&#xff0c;检测各种依赖库&#xff0c;发现并没有少什么。后来发现支付宝demo里比文档讲解里面多两个.a文件 直接加上就好了 转载于:https://www.cnblogs.com/OIMM/p/7655776.html...

十堰h5网站建设/b2b电子商务平台网站

玩zabbix已经几年了&#xff0c;一直想分享一些相关的使用经验和心得&#xff0c;但是总以各种借口而拖延&#xff0c;最近准备重新整理&#xff0c;记录一些实际工作环境中的示例&#xff0c;一方面希望能够帮助正在学习或者正在寻找这方面资料的朋友&#xff0c;另一方面也是…...

做视频网站怎么挣钱吗/网站优化 秦皇岛

今天開始学习Libevent 。Libevent 是开源社区的一款高性能I/O框架库。主要特点有&#xff1a; 1 跨平台。 2 统一事件源 3 线程安全 4 基于Reactor 今天主要进行了Libevent的安装&#xff0c;以及利用libevent框架编写一个间隔1s打印 Hello Libevent&#xff01;信息的程序…...

日照社保网站开发中什么意思/如何做地推推广技巧

1. Shell概述 1.1 概念 这里可以分两个方面来理解&#xff1a; 是一个命令行解释器。它为用户提供了一个像Linux内核发送请求以便运行程序的界面系统程序&#xff0c;用户可以通过shell来启动、挂起、停止甚至是编写一些程序。shell还是一个功能相当强大的编程语言&#xff0…...

辽宁建设官方网站/百度关键词优化策略

前语&#xff1a;不要为了读文章而读文章&#xff0c;一定要带着问题来读文章&#xff0c;勤思考。在此&#xff0c;建议大家为本公众号加“星标”。如文章写得好&#xff0c;望大家阅读后在右下边“在看”处点个赞&#xff0c;以示鼓励&#xff01;作者:LiWenD 来源&#xff…...

淄博哪里有网站建设平台/产品怎么做市场推广

1.原因&#xff1a;刚进入这家公司&#xff0c;给同事交接完&#xff0c;直接使用他的电脑&#xff0c;每次提交代码都显示他的用户名&#xff0c;本以为是电脑系统名称呢&#xff0c;可是修改了之后没有效果 2.解决方案&#xff1a; 打开C盘里的 .gitconfig文件 看下git的用户…...