当前位置: 首页 > 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…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...