mybatis多條件in查詢的實(shí)現(xiàn)
最近碰上有個業(yè)務(wù),查詢的sql如下:
select * from table where (sku_id,batch_no) in ((#{skuId},#{batchNo}),...); 本來也沒什么,很簡單常見的一種sql。問題是我們使用的是mybatis-plus,然后寫的時(shí)候又沒有考慮到后面的查詢條件,這里用的是mybatis-plus lambda的方式。
LambdaQueryChainWrapper<Table> query = tableService.lambdaQuery(); query.eq(Table::getId, param.getId());
但是mysql-plus并沒有支持這種sql的形式,要么用apply方法自定義拼接sql,要么不采用lambda方式,將語句寫成 xml 形式。
不過,第一種方式感覺很 low,一大段 java 代碼里插入一段sql字符串,看上去就很別扭,因?yàn)橛悬c(diǎn)代碼潔癖,只能果斷放棄。
第二種改動又太大,前面那么多查詢條件,又要全部移入xml里面,同時(shí),本來已經(jīng)通過測試的篩選條件,又要重新來一遍,太懶,實(shí)在干不動了。
想想這么常見的場景,網(wǎng)上理應(yīng)有現(xiàn)成的解決方案。但不知道是搜索關(guān)鍵字不對還是確實(shí)沒有,搜了半天沒搜出來。
最后無奈,只能嘗試自己擴(kuò)展一下。
代碼
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 設(shè)置
* </p>
*
* @param columns 查詢字段
*/
@SafeVarargs
public 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;
}
@Override
public String getSqlSelect() {
return sqlSelect;
}
/**
* <p>
* 用于生成嵌套 sql
* 故 sqlSelect 不向下傳遞
* </p>
*/
@Override
protected 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查詢參數(shù)長度");
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));到此這篇關(guān)于mybatis多條件in查詢的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)mybatis多條件in查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過Java實(shí)現(xiàn)對PDF頁面的詳細(xì)設(shè)置
這篇文章主要介紹了通過Java實(shí)現(xiàn)對PDF頁面的詳細(xì)設(shè)置,下面的示例將介紹通過Java編程來對PDF頁面進(jìn)行個性化設(shè)置的方法,包括設(shè)置頁面大小、頁邊距、紙張方向、頁面旋轉(zhuǎn)等,需要的朋友可以參考下2019-07-07
java初學(xué)者如何讓編程學(xué)習(xí)起來更簡單
我們給大家?guī)硪黄P(guān)于java初學(xué)者如何讓編程學(xué)習(xí)起來更簡單的基礎(chǔ)性文章,有需要的朋友們可以學(xué)習(xí)下。2020-11-11
spring中@RestController和@Controller的區(qū)別小結(jié)
@RestController和@Controller這兩個注解用于創(chuàng)建Web應(yīng)用程序的控制器類,那么這兩個注解有哪些區(qū)別,本文就來介紹一下,并用示例代碼說明,感興趣的可以了解一下2023-09-09
Spring boot實(shí)現(xiàn)一個簡單的ioc(2)
這篇文章主要為大家詳細(xì)介紹了Spring boot實(shí)現(xiàn)一個簡單ioc的第二篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
java動態(tài)目錄樹的實(shí)現(xiàn)示例
在開發(fā)過程中,常常需要對目錄結(jié)構(gòu)進(jìn)行操作和展示,本文主要介紹了java動態(tài)目錄樹的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Java中MapStruct轉(zhuǎn)換實(shí)體的步驟實(shí)現(xiàn)
本文主要介紹了Java中MapStruct轉(zhuǎn)換實(shí)體的步驟實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2026-03-03
詳解Spring中Spel表達(dá)式和el表達(dá)式的區(qū)別
在?Java?開發(fā)中,表達(dá)式語言是一種強(qiáng)大的工具,而SpEL?表達(dá)式與EL?表達(dá)式是我們常常遇到兩種表達(dá)式語言,下面我們就來看看它們的具體使用與區(qū)別吧2023-07-07

