国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

MyBatis-Plus中LambdaQueryWrapper的探究

這篇具有很好參考價(jià)值的文章主要介紹了MyBatis-Plus中LambdaQueryWrapper的探究。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

MyBatis-Plus的條件構(gòu)造器LambdaQueryWrapper是開發(fā)中常用的工具,和普通的QueryWrapper不同的是,LambdaQueryWrappe

可以識(shí)別Lambda表達(dá)式,獲取Lambda表達(dá)式對(duì)應(yīng)的字段名稱,在使用上更方便,此外,當(dāng)對(duì)象的字段發(fā)生變更時(shí)也更安全。

我們知道,Lambda表達(dá)式本質(zhì)上是一個(gè)匿名內(nèi)部類,實(shí)現(xiàn)了Function,重寫了apply方法。比如下面這樣的:

// Lambda表達(dá)式
User::getName
// 匿名內(nèi)部類
new SFunction<User, String>() {
    @Override
    public String apply(User user) {
        return user.getName();
    }
}

那么LambdaQueryWrapper是怎么獲取到Lambda表達(dá)式對(duì)應(yīng)的字段名稱的呢?

看一下AI的解答:LambdaQueryWrapper之所以能獲取到Lambda表達(dá)式所對(duì)應(yīng)的字段名稱,實(shí)際上并沒有采用通過實(shí)例化對(duì)象并逐個(gè)字段賦值的方式來(lái)比較結(jié)果這么復(fù)雜的手段。而是巧妙地利用了Java 8中Lambda表達(dá)式的序列化機(jī)制。

在Java 8中,Lambda表達(dá)式會(huì)被編譯為一個(gè)實(shí)現(xiàn)了java.lang.invoke.SerializedLambda接口的類的實(shí)例。這個(gè)SerializedLambda實(shí)例保存了生成它的類、方法簽名以及對(duì)應(yīng)方法的參數(shù)索引等信息。MyBatis-Plus正是利用了這一特性,通過反射調(diào)用Lambda表達(dá)式的writeReplace方法得到SerializedLambda對(duì)象,進(jìn)而從中解析出字段名。

具體來(lái)說,MyBatis-Plus內(nèi)部會(huì)將Lambda表達(dá)式轉(zhuǎn)換為SerializedLambda對(duì)象進(jìn)行反序列化處理,然后分析SerializedLambda對(duì)象中的方法描述符和其他相關(guān)信息,從而準(zhǔn)確地定位到Lambda表達(dá)式中引用的實(shí)體類屬性字段。這樣就無(wú)需實(shí)際操作實(shí)例對(duì)象,也能智能地構(gòu)建SQL查詢條件所需的字段名。

從個(gè)人角度來(lái)思考,我們可以通過反射獲取到apply方法,進(jìn)而知道方法的參數(shù)是一個(gè)User,拿到User.class,但是似乎就止步于此了,反射對(duì)apply方法的內(nèi)部構(gòu)造 return user.getName()似乎是無(wú)能為力的。

也許可以通過newInstance方法獲取User實(shí)例,給實(shí)例的每一個(gè)字段賦不同值,然后調(diào)用Lambda表達(dá)式得到結(jié)果,進(jìn)行一一對(duì)比?先不說如何給字段賦值,簡(jiǎn)單的String,Integer等基本類型倒是好說,集合類型呢,復(fù)雜的對(duì)象類型呢?這樣也太蠢了,而且也并不是所有的對(duì)象都可以簡(jiǎn)單的實(shí)例化的。那么MyBatis-Plus又是怎么實(shí)現(xiàn)這樣的邏輯的呢?先說結(jié)論吧,是通過序列化反序列化的方法獲取到的字段名稱。
看源碼:先從LambdaQueryWrapper中隨便挑個(gè)帶有SFunction參數(shù)的方法,一路向下找,在AbstractLambdaWrapper類下面會(huì)找到這樣一個(gè)方法

private String getColumn(SerializedLambda lambda, boolean onlyColumn) {
    Class<?> aClass = lambda.getInstantiatedType();
    this.tryInitCache(aClass);
    String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
    ColumnCache columnCache = this.getColumnCache(fieldName, aClass);
    return onlyColumn ? columnCache.getColumn() : columnCache.getColumnSelect();
}

可以看到是通過lambda.getImplMethodName方法拿到了一個(gè)方法名稱,然后通過PropertyNamer.methodToProperty方法得到對(duì)應(yīng)的屬性名稱。后面的步驟我們都會(huì),implMethodName是lambda對(duì)象的一個(gè)屬性,那么我們的關(guān)注點(diǎn)就要放在這個(gè)方法的參數(shù)SerializedLambda lambda上了。我們往回看,

protected String columnToString(SFunction<T, ?> column, boolean onlyColumn) {
    return this.getColumn(LambdaUtils.resolve(column), onlyColumn);
}

LambdaUtils.resolve(column)方法

public static <T> SerializedLambda resolve(SFunction<T, ?> func) {
    Class<?> clazz = func.getClass();
    String name = clazz.getName();
    return (SerializedLambda)Optional.ofNullable((WeakReference)FUNC_CACHE.get(name)).map(Reference::get).orElseGet(() -> {
        SerializedLambda lambda = SerializedLambda.resolve(func);
        FUNC_CACHE.put(name, new WeakReference(lambda));
        return lambda;
    });
}

這兒主要是一個(gè)緩存的作用,關(guān)于這個(gè)緩存,值得一提的是,雖然MyBatis-Plus這兒用的是clazz.getName,但是實(shí)際測(cè)試后發(fā)現(xiàn)同一個(gè)class下同一個(gè)位置的Lambda表達(dá)式,即使在多線程環(huán)境中,也會(huì)復(fù)用同一個(gè)對(duì)象。因此即使這兒用func做緩存的key,理論上也是可以的。我們繼續(xù)往下看,找到SerializedLambda.resolve方法

public static SerializedLambda resolve(SFunction<?, ?> lambda) {
		if (!lambda.getClass().isSynthetic()) {
			throw ExceptionUtils.mpe("該方法僅能傳入 lambda 表達(dá)式產(chǎn)生的合成類", new Object[0]);
		} else {
			try {
				// 先序列化成byte[],在封裝成ObjectInputStream
				ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(SerializationUtils.serialize(lambda))) {
					protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
						Class clazz;
						try {
							clazz = ClassUtils.toClassConfident(objectStreamClass.getName());
						} catch (Exception var4) {
							clazz = super.resolveClass(objectStreamClass);
						}

						// 這兒用自定義的SerializedLambda替換java原生的SerializedLambda
						return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
					}
				};

				SerializedLambda var2;
				try {
					// 反序列化成SerializedLambda
					var2 = (SerializedLambda) objIn.readObject();
				} catch (Throwable var5) {
					try {
						objIn.close();
					} catch (Throwable var4) {
						var5.addSuppressed(var4);
					}

					throw var5;
				}

				objIn.close();
				return var2;
			} catch (IOException | ClassNotFoundException var6) {
				0
				throw ExceptionUtils.mpe("This is impossible to happen", var6, new Object[0]);
			}
		}
	}

可以看到,在這個(gè)方法中主要做了3件事

1.將Lambda表達(dá)式序列化,

2.將序列化后的Lambda表達(dá)式反序列化,

3.使用自定義的SerializedLambda頂替java原生的SerializedLambda作為反序列化結(jié)果。

那么問題來(lái)了,按照正常的思維,我們將一個(gè)對(duì)象序列化,再反序列化,應(yīng)該得到這個(gè)對(duì)象的本身,為什么會(huì)得到一個(gè)SerializedLambda呢?要弄明白這個(gè)問題,我們還得回頭看看SerializedLambda的源碼介紹,開頭有這樣一段話

 * <p>Implementors of serializable lambdas, such as compilers or language
 * runtime libraries, are expected to ensure that instances deserialize properly.
 * One means to do so is to ensure that the {@code writeReplace} method returns
 * an instance of {@code SerializedLambda}, rather than allowing default
 * serialization to proceed.
翻譯:可序列化lambda的實(shí)現(xiàn)程序(如編譯器或語(yǔ)言運(yùn)行庫(kù))應(yīng)確保實(shí)例正確反序列化。
這樣做的一種方法是確保{@code writeReplace}方法返回{@code SerializedLambda}的實(shí)例,而不是允許默認(rèn)序列化繼續(xù)進(jìn)行。

提取幾個(gè)關(guān)鍵詞,可序列化的Lambda,writeReplace,序列化。

先說可序列化的Lambda,回頭看LambdaQueryWrapper的參數(shù),是一個(gè)SFunction,除了實(shí)現(xiàn)了Function外,還實(shí)現(xiàn)了Serializable,確實(shí)滿足可序列化的Lambda的條件。也就是說,文章最開頭匿名內(nèi)部類的寫法是錯(cuò)誤的,不支持的。

再往后,提到了writeReplace方法,我們?nèi)绻淳幾g后的class文件,可以看到Lambda表達(dá)式里面出現(xiàn)了一個(gè)writeReplace方法,那么,我們可不可以使用反射直接調(diào)用這個(gè)方法呢?答案是可以的。

public SerializedLambda getSerializedLambda(SFunction<?, ?> column){
    Class<?> columnClass = column.getClass();
    if (!columnClass.isSynthetic()) {
        throw new RuntimeException("該方法僅能傳入lambda表達(dá)式產(chǎn)生的合成類");
    }
    Method writeReplace;
    try {
        writeReplace = columnClass.getDeclaredMethod("writeReplace");
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
    }
    writeReplace.setAccessible(true);

    SerializedLambda serializedLambda;
    try {
        serializedLambda = (SerializedLambda) writeReplace.invoke(column);
    } catch (IllegalAccessException | InvocationTargetException e) {
        throw new RuntimeException("解析失敗Lambda表達(dá)式失敗");
    }
}

這樣的代碼同樣可以獲取到SerializedLambda對(duì)象,并且由于省略的反序列化的過程,性能上是要比MyBatis-Plus的那種方法要快的。至于MyBatis-Plus為什么不用這種方法,我們就無(wú)從得知了。

最后總結(jié)一下:

1. LambdaQueryWrapper中的SFunction只能用Lambda表達(dá)式,不能用內(nèi)部類。
2. 可序列化的Lambda表達(dá)式在編譯后會(huì)生成一個(gè)writeReplace方法,返回值是一個(gè)SerializedLambda對(duì)象。
3. SerializedLambda對(duì)象中包含了很多Lambda表達(dá)式的詳細(xì)信息,比如實(shí)現(xiàn)的方法名稱等。
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-793698.html

到了這里,關(guān)于MyBatis-Plus中LambdaQueryWrapper的探究的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Mybatis Plus中使用LambdaQueryWrapper進(jìn)行分頁(yè)以及模糊查詢對(duì)比傳統(tǒng)XML方式進(jìn)行分頁(yè)

    Mybatis Plus中使用LambdaQueryWrapper進(jìn)行分頁(yè)以及模糊查詢對(duì)比傳統(tǒng)XML方式進(jìn)行分頁(yè)

    傳統(tǒng)的XML方式只能使用limit以及offset進(jìn)行分頁(yè),通過判斷name和bindState是否為空,不為空則拼接條件。 只需要在Service實(shí)現(xiàn)類中直接調(diào)用Mybatis Plus的方法即可進(jìn)行操作。 return PageSanitationCompanyStaff類型可以得到數(shù)據(jù)的總數(shù),你也可以通過.getRecords()方式獲取List集合 這樣子,我們就

    2024年02月12日
    瀏覽(19)
  • 【Mybatis-Plus】Mybatis-Plus快速入門

    Mybatis-Plus是基于Mybatis的數(shù)據(jù)庫(kù)操作組件,其實(shí)現(xiàn)的功能完全是Mybatis的功能拓展,不改變Mybatis的使用方式,可以兼容Mybatis的操作方式。 創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)、一個(gè)表進(jìn)行基礎(chǔ)操作: 創(chuàng)建一個(gè)Spring項(xiàng)目,項(xiàng)目通過Spring Initlizer創(chuàng)建,不導(dǎo)入任何依賴包,在POM.xml文件中進(jìn)行依賴導(dǎo)入

    2024年02月07日
    瀏覽(28)
  • Mybatis-Plus 進(jìn)階開發(fā) -- Mybatis-Plus 入門教程(二)

    Mybatis-Plus 進(jìn)階開發(fā) -- Mybatis-Plus 入門教程(二)

    為了鞏固所學(xué)的知識(shí),作者嘗試著開始發(fā)布一些學(xué)習(xí)筆記類的博客,方便日后回顧。當(dāng)然,如果能幫到一些萌新進(jìn)行新技術(shù)的學(xué)習(xí)那也是極好的。作者菜菜一枚,文章中如果有記錄錯(cuò)誤,歡迎讀者朋友們批評(píng)指正。 (博客的參考源碼可以在我主頁(yè)的資源里找到,如果在學(xué)習(xí)的

    2024年02月10日
    瀏覽(32)
  • Mybatis-Plus(三)--Mybatis-Plus配置和條件構(gòu)造器

    在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,詳情:https://mybatis.plus/config 【1】configLocation--自己?jiǎn)为?dú)的MyBatis配置的路徑 SpringMVC的xml中寫法: 【2】mapperLocations--MyBatis Mapper所對(duì)應(yīng)的XML文件位置 如果你在Mapper中有自定義方法(XML中有自定義實(shí)現(xiàn)

    2024年02月15日
    瀏覽(27)
  • Mybatis-Plus通用枚舉功能 [MyBatis-Plus系列] - 第493篇

    Mybatis-Plus通用枚舉功能 [MyBatis-Plus系列] - 第493篇

    歷史文章( 文章 累計(jì)490+) 《國(guó)內(nèi)最全的Spring?Boot系列之一》 《國(guó)內(nèi)最全的Spring?Boot系列之二》 《

    2024年02月08日
    瀏覽(21)
  • mybatis-plus分頁(yè)total為0,分頁(yè)失效,mybatis-plus多租戶插件使用

    背景:項(xiàng)目使用mybatis分頁(yè)插件不生效,以及多租戶使用時(shí)讀取配置異常 多租戶插件使用遇到的問題: 最開始在MyTenantLineHandler中使用 @Value(\\\"${tables}\\\"),服務(wù)啟動(dòng)時(shí)能從配置中心拉取到配置,但在運(yùn)行時(shí)獲取到的值為空,試了很多方法都不生效,后面將配置中心的配置在調(diào)用My

    2024年02月06日
    瀏覽(22)
  • Mybatis-Plus

    Mybatis-Plus

    官方網(wǎng)站 ? ? MyBatis-Plus(簡(jiǎn)稱 MP)是一個(gè) MyBatis的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生。我們的愿景是成為 MyBatis 最好的搭檔,就像 魂斗羅 中的 1P、2P,基友搭配,效率翻倍。 ? 無(wú)侵入 :只做增強(qiáng)不做改變,引入它不會(huì)對(duì)現(xiàn)有工程產(chǎn)

    2024年01月15日
    瀏覽(19)
  • 【MyBatis-Plus】MyBatis進(jìn)階使用

    【MyBatis-Plus】MyBatis進(jìn)階使用

    目錄 一、MyBatis-Plus簡(jiǎn)介 1.1 介紹 1.2 優(yōu)點(diǎn) 1.3 結(jié)構(gòu) 二、MyBatis-Plus基本使用 2.1 配置 2.2 代碼生成 2.3 CRUD接口測(cè)試 三、MyBatis-Plus策略詳解 3.1 主鍵生成策略 3.2 雪花ID生成器 3.3 字段自動(dòng)填充策略 3.4 邏輯刪除 四、MyBatis-Plus插件使用 4.1?樂觀鎖插件 4.1.1?什么是樂觀鎖和悲觀鎖? 4.

    2024年02月04日
    瀏覽(21)
  • mybatis升級(jí)到mybatis-plus

    mybatis升級(jí)到mybatis-plus,兩個(gè)共存 之前依賴只有mybatis,沒有plus 做法: 修改之后的依賴 更換 完整配置代碼 1.添加plus的插件 注入 3.完整代碼 就是上面升級(jí)plus 的代碼. 參考文章:https://www.likecs.com/show-308411339.html

    2024年02月11日
    瀏覽(21)
  • Mybatis 框架 ( 三 ) Mybatis-Plus

    Mybatis 框架 ( 三 ) Mybatis-Plus

    官網(wǎng) : https://www.baomidou.com/ MyBatis-Plus 是一個(gè) MyBatis 的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上封裝了大量常規(guī)操作,減少了SQL的編寫量。 使用時(shí)通常通過Springboot框架整合使用 并且使用Lombok框架簡(jiǎn)化實(shí)體類 重點(diǎn)注意 : 與 SpringBoot整合時(shí), 在啟動(dòng)類增加注解 @MapperScan(\\\"mapper接口路徑 \\\") 或者

    2024年02月01日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包