Java 高并發(fā)編程之最實(shí)用的任務(wù)執(zhí)行架構(gòu)設(shè)計(jì)建議收藏
前言
隨著互聯(lián)網(wǎng)與軟件的發(fā)展,除了程序員,架構(gòu)師也是越來(lái)越火的職業(yè)。他們伴隨著項(xiàng)目的整個(gè)生命過(guò)程,他們更像是傳統(tǒng)工業(yè)的設(shè)計(jì)師,將項(xiàng)目當(dāng)做生命一般細(xì)心雕琢。
目前對(duì)于項(xiàng)目架構(gòu)而言,基本都會(huì)需要設(shè)計(jì)的幾個(gè)架構(gòu)。
1、業(yè)務(wù)架構(gòu)
項(xiàng)目或者產(chǎn)品的市場(chǎng)定位、需求范圍、作用場(chǎng)景都是需要在項(xiàng)目啟動(dòng)初期進(jìn)行系統(tǒng)性分析的。在設(shè)計(jì)業(yè)務(wù)架構(gòu)中,架構(gòu)師還需要明確角色。我看過(guò)很多關(guān)于架構(gòu)的文章,談到角色的很少。
什么是角色?
例如:商場(chǎng)作為一個(gè)整體系統(tǒng),角色就有消費(fèi)者、店員、收費(fèi)員、保安等等。各個(gè)角色完成好自己角色所需要承擔(dān)的任務(wù),整體系統(tǒng)就能完美的運(yùn)行。
對(duì)應(yīng)到軟件系統(tǒng)中,根據(jù)產(chǎn)品的定位和需求,也會(huì)有著對(duì)照的角色,比如:用戶(hù)、數(shù)據(jù)審核者、產(chǎn)品制作者、運(yùn)維人員等。在項(xiàng)目啟動(dòng)初期,架構(gòu)師需要對(duì)項(xiàng)目中的每個(gè)角色做好職責(zé)定位,我相信在這點(diǎn)上,大部分開(kāi)發(fā)同學(xué)在工作中,或多或少都有過(guò)職責(zé)不明確帶來(lái)的困擾。

2、技術(shù)架構(gòu)
在軟件項(xiàng)目研發(fā)過(guò)程中,我們會(huì)用到許多外部組件。在使用組件中,架構(gòu)師必須結(jié)合業(yè)務(wù)需求合理的選擇各個(gè)組件。項(xiàng)目是個(gè)生命,她會(huì)成長(zhǎng),架構(gòu)師需要明白如果一開(kāi)始就選擇重量級(jí)組件會(huì)讓還是個(gè)孩童的項(xiàng)目不受重負(fù),架構(gòu)師也需要明白如果技術(shù)架構(gòu)的設(shè)計(jì)不具備拓展性,那么這個(gè)孩子無(wú)法茁壯成長(zhǎng)。所以技術(shù)架構(gòu)尤為重要。

3、物理架構(gòu)
物理架構(gòu)又叫做部署架構(gòu),項(xiàng)目產(chǎn)品如果要在生產(chǎn)環(huán)境穩(wěn)定運(yùn)行,一個(gè)穩(wěn)定又高效的物理架構(gòu)是必不可少的。而且往往物理架構(gòu)和技術(shù)架構(gòu)是相輔相成的,性能監(jiān)控、異常告警、業(yè)務(wù)日志等等設(shè)計(jì),都是為了讓項(xiàng)目做更好的自己。

高并發(fā)任務(wù)執(zhí)行架構(gòu)
在我十年的工作中,業(yè)務(wù)相關(guān)、中間件、大數(shù)據(jù)都有做過(guò)。本文主要分享一下高并發(fā)任務(wù)執(zhí)行框架設(shè)計(jì),會(huì)由淺入深的講述一下設(shè)計(jì)演化過(guò)程。如果你不只是想做業(yè)務(wù)后端開(kāi)發(fā),那么本文會(huì)給你一個(gè)全新的視野。
需求場(chǎng)景
我們列一下該項(xiàng)目的需求場(chǎng)景,看看工作中是否遇到過(guò)。
1、有個(gè)復(fù)雜的數(shù)據(jù)需要制作,而且制作的時(shí)間很長(zhǎng),無(wú)法讓請(qǐng)求方持續(xù)等待。所以請(qǐng)求方只能給你個(gè)回調(diào)地址,需要你完成這個(gè)制作后將產(chǎn)物通知他。
2、復(fù)雜的制作過(guò)程需要消耗資源,而且資源有限,無(wú)法無(wú)限量提供。如果你有接觸過(guò)AI,就會(huì)比較了解資源有限的感受。除了ASR、TTS這類(lèi)識(shí)別類(lèi)型的AI功能能做到近實(shí)時(shí)的反饋,大部分的算法在運(yùn)行的時(shí)候都會(huì)消耗整張顯卡,而且耗時(shí)很長(zhǎng)。
初看場(chǎng)景,很多后端可能會(huì)第一時(shí)間想到elastic-job(一個(gè)分布式任務(wù)調(diào)度框架)。即便你熟悉使用elastic-job,一開(kāi)始就選擇重框架是不是有種殺雞用牛刀的感覺(jué)。不著急,我們一步步分析,一步步設(shè)計(jì)。
業(yè)務(wù)架構(gòu)設(shè)計(jì)
高度抽象一下我們的業(yè)務(wù),對(duì)產(chǎn)品設(shè)計(jì)者而言,貌似是個(gè)簡(jiǎn)單的不能再簡(jiǎn)單的東西。等到了技術(shù)架構(gòu),我們深入分析其中演化的功能點(diǎn),就會(huì)發(fā)現(xiàn)這是個(gè)龐大的機(jī)器。我們先給他起個(gè)簡(jiǎn)單的名字:Task Execution Engine(縮寫(xiě):TEE)

技術(shù)架構(gòu)設(shè)計(jì)
下面我們開(kāi)始進(jìn)行核心模塊的技術(shù)架構(gòu)設(shè)計(jì),按照我們的初始需求開(kāi)始我們的設(shè)計(jì)旅程。
初始設(shè)計(jì)

設(shè)計(jì)說(shuō)明:
1、業(yè)務(wù)后端發(fā)出q1請(qǐng)求,我們首先需要對(duì)該請(qǐng)求的參數(shù)做矯正,為了可用性考慮。
2、參數(shù)校驗(yàn)過(guò)后,給到執(zhí)行引擎模塊。執(zhí)行引擎主要的職責(zé)有從資源表獲取資源數(shù)據(jù)、將任務(wù)參數(shù)與資源參數(shù)封裝到任務(wù)對(duì)象內(nèi)、將任務(wù)提交線(xiàn)程池。有一點(diǎn)要說(shuō)明執(zhí)行引擎最好使用隊(duì)列模式,任務(wù)先進(jìn)隊(duì)列,可以通過(guò)while循環(huán)方式或者定時(shí)線(xiàn)程池都可以,后面會(huì)推薦更好的。
3、任務(wù)執(zhí)行的狀態(tài)與結(jié)果需要同步到數(shù)據(jù)庫(kù)中,建議使用mysql。
小結(jié):
按照初始需求,該設(shè)計(jì)相對(duì)比較簡(jiǎn)單,完全夠用了。但是按照產(chǎn)品的迭代,業(yè)務(wù)方的需求不會(huì)僅限于此。繼續(xù)演化。
演化階段一
隨著業(yè)務(wù)的上線(xiàn),業(yè)務(wù)端會(huì)馬上迎來(lái)新的問(wèn)題。
1、由于提交的任務(wù)太多了,排在后面的任務(wù)遲遲無(wú)法等到自己獲取到資源執(zhí)行任務(wù)。當(dāng)然我們可以完全靠增加資源來(lái)解決,但是資源的數(shù)量在產(chǎn)品前期是不可知的。所以需要有一些策略,比如讓用戶(hù)可以取消自己任務(wù),而不是一直等待。
2、任務(wù)的種類(lèi)開(kāi)始增加,業(yè)務(wù)端不滿(mǎn)足于單一制作,開(kāi)始要求多樣化。
3、任務(wù)的執(zhí)行過(guò)程開(kāi)始需要用到其他資源,不再是一個(gè)資源對(duì)一個(gè)任務(wù)的模式了。
4、任務(wù)的整體執(zhí)行情況不可知,需要一定的量化分析,至少讓業(yè)務(wù)組知道每天的任務(wù)成功率。
按照需求進(jìn)行第二版的設(shè)計(jì),在盡量不改變?cè)瓉?lái)整體設(shè)計(jì)的情況下,補(bǔ)充功能。

設(shè)計(jì)說(shuō)明:
1、為了解決排隊(duì)問(wèn)題,增加了雙隊(duì)列算法來(lái)解決。用圖解的方式解釋一下雙隊(duì)列。

邏輯簡(jiǎn)單說(shuō)明一下,任務(wù)優(yōu)先提交至執(zhí)行隊(duì)列,引擎的定時(shí)讀取隊(duì)列的順序優(yōu)先為等待隊(duì)列。如果等待隊(duì)列中的任務(wù)可以獲取所需資源,則立即啟動(dòng)線(xiàn)程執(zhí)行,否則原封不動(dòng)回到等待隊(duì)列。引擎其次讀取執(zhí)行隊(duì)列,如果無(wú)法獲取資源則進(jìn)入等待隊(duì)列,如獲取資源,則立即啟動(dòng)線(xiàn)程執(zhí)行。
那么取消隊(duì)列,則只需要將隊(duì)列中的任務(wù)踢出隊(duì)列即可。在送回隊(duì)里的過(guò)程中,一定要保證隊(duì)列的有序性。
2、創(chuàng)建了任務(wù)池,增加了任務(wù)封裝層,在任務(wù)池中挑選需要執(zhí)行的任務(wù)類(lèi)。
3、增加了策略機(jī)模塊,添加資源調(diào)度策略,由資源調(diào)度策略堆任務(wù)所需資源合理分配。可以由業(yè)務(wù)方提供分配方案,盡可能保證任務(wù)的公平性。
4、數(shù)據(jù)庫(kù)增加統(tǒng)計(jì)表,可以考慮使用定時(shí)任務(wù),將任務(wù)表的數(shù)據(jù)統(tǒng)計(jì)存入統(tǒng)計(jì)表。
小結(jié):
現(xiàn)在看上去已經(jīng)比較完善了,合理了任務(wù)調(diào)度、增加了任務(wù)種類(lèi)、合理的資源調(diào)度,好像還不錯(cuò)。但是產(chǎn)品總會(huì)有新要求的,那么繼續(xù)演化。
演化階段二
漸漸的,你設(shè)計(jì)的引擎還不錯(cuò)。那么新的挑戰(zhàn)來(lái)了。
1、更多的業(yè)務(wù)方找到你,希望也使用你的項(xiàng)目進(jìn)行任務(wù)制作,但是他們并不想共享資源,而是希望有自己的獨(dú)立資源,和獨(dú)立的隊(duì)列。但并不是所有的資源都需要獨(dú)立,一些可以支持高并發(fā)的資源,是可以共享的。簡(jiǎn)而言之,更多的業(yè)務(wù)方,由業(yè)務(wù)方為維度的獨(dú)立隊(duì)列,獨(dú)立和共享的資源分配。
2、業(yè)務(wù)方找到你,說(shuō)如果把任務(wù)1的結(jié)果給到任務(wù)2,其實(shí)就能拿到我要的結(jié)果。問(wèn)題來(lái)了,原子任務(wù)要具備可以編排成復(fù)雜任務(wù)的能力。
3、任務(wù)的狀態(tài)過(guò)程無(wú)法監(jiān)控。OK,任務(wù)狀態(tài)機(jī)。
4、既然大家都需要對(duì)接你的項(xiàng)目,能不能提供標(biāo)準(zhǔn)的sdk,我只需要引入就可以完美的對(duì)接你的系統(tǒng)。
5、相同的任務(wù)參數(shù),是不是制作出來(lái)的結(jié)果一致呢?那么是否需要增加結(jié)果緩存,降低對(duì)資源的消耗呢?
6、完正的生產(chǎn)項(xiàng)目必然需要將日志、告警等關(guān)鍵信息傳遞出來(lái),一旦發(fā)生問(wèn)題可以馬上定位到問(wèn)題的起因。
這些問(wèn)題對(duì)于新人來(lái)說(shuō)還是很有挑戰(zhàn)的,需要對(duì)系統(tǒng)深層的含義有充足的理解。沒(méi)事,我來(lái)好好來(lái)說(shuō)下設(shè)計(jì)所需要掌握的知識(shí)點(diǎn)。

設(shè)計(jì)說(shuō)明:
1、需要在資源表中區(qū)別資源類(lèi)型,共享資源組所有業(yè)務(wù)組都可以使用,獨(dú)立資源則資源具備業(yè)務(wù)標(biāo)識(shí)。在執(zhí)行引擎的隊(duì)列管理中,也需要區(qū)分業(yè)務(wù)組,避免共用排隊(duì)。這里給一個(gè)建議,共享的資源一定要是可以支持并發(fā)或者可以部署多個(gè)實(shí)例的,避免所有的業(yè)務(wù)組產(chǎn)品制作癱瘓。
2、增加了高級(jí)任務(wù)概念,高級(jí)任務(wù)可以將任意的原子任務(wù)進(jìn)行組合編排,形成全新的任務(wù)。需要定義專(zhuān)屬于TEE的語(yǔ)法規(guī)則。對(duì)語(yǔ)法規(guī)則引擎的開(kāi)發(fā),有一些建議。你可能會(huì)選擇規(guī)則引擎,建議其實(shí)可以自己開(kāi)發(fā),畢竟語(yǔ)法不會(huì)太過(guò)復(fù)雜,沒(méi)必要引入三方的引擎。

3、增加任務(wù)狀態(tài)機(jī),執(zhí)行引擎在提交線(xiàn)程的同時(shí),也想任務(wù)狀態(tài)機(jī)提交任務(wù)線(xiàn)程信息。任務(wù)的進(jìn)度狀態(tài)可以同步給任務(wù)狀態(tài)機(jī)中,同時(shí)一旦任務(wù)執(zhí)行過(guò)長(zhǎng)的時(shí)間,除了任務(wù)自己的超時(shí)機(jī)制外,也可由狀態(tài)機(jī)的看門(mén)狗程序?qū)⒖ㄋ谰€(xiàn)程釋放、資源回收。
4、研發(fā)屬于TEE的SDK,作為內(nèi)部系統(tǒng)不建議SDK增加鑒權(quán)模塊。畢竟你對(duì)接的往往都是業(yè)務(wù)后端,鑒權(quán)不通過(guò)的話(huà)根本滲透不到TEE層面。給開(kāi)發(fā)SDK一些建議,盡量引用較少的包,避免業(yè)務(wù)端引入帶來(lái)的包沖突。SDK也需要添加一些回調(diào)Consumer或者Function,盡可能讓業(yè)務(wù)端對(duì)接起來(lái)代碼簡(jiǎn)單。
5、增加了緩存策略,可以設(shè)想一下,大部分情況下,相同的參數(shù)制作出來(lái)的結(jié)果也必然相同。使用redis,將任務(wù)參數(shù)與任務(wù)結(jié)果進(jìn)行緩存,主鍵可以采用任務(wù)參數(shù)的MD5值。任務(wù)在提交給任務(wù)執(zhí)行引擎前,檢查緩存中是否已經(jīng)存在結(jié)果。緩存的過(guò)期時(shí)間按照具體情況而定。

6、增加日志系統(tǒng)和監(jiān)控系統(tǒng)的對(duì)接,狀態(tài)機(jī)與任務(wù)執(zhí)行中的信息接入到日志系統(tǒng)中。對(duì)于日志系統(tǒng)的建議是,最好采用成熟的ELK架構(gòu)??梢钥紤]兩種方式
a、將日志異步推送到消息隊(duì)列(例如:kafka),使用flink將kafka存入es。
b、使用logstash將日志內(nèi)容清洗處理,推送到es。
兩種方式都可以,但是一定要異步推送日志,避免任務(wù)阻塞。
告警系統(tǒng)的接入可以使用Prometheus,將TEE的指標(biāo)信息開(kāi)放出來(lái),特別是告警信息。在Prometheus的告警監(jiān)控規(guī)則中,可以將告警信息按照某些策略發(fā)送郵件或者短信,通知運(yùn)維人員。

小結(jié):
做到這里,我們?cè)倏纯次覀兊募夹g(shù)架構(gòu)圖,是不是感到很滿(mǎn)足。但是這真的夠了嗎?
演化階段三
隨著業(yè)務(wù)愈發(fā)繁重,一個(gè)新的問(wèn)題出現(xiàn)。
1、TEE在本機(jī)運(yùn)行很順利,但是每個(gè)任務(wù)都是需要消耗線(xiàn)程的,單臺(tái)模式線(xiàn)程必然不是無(wú)限的,總有吃滿(mǎn)的時(shí)候。問(wèn)題來(lái)了,TEE得支持分布式部署結(jié)構(gòu)。但是有資源管理的存在,你無(wú)法通過(guò)加實(shí)例的方式來(lái)實(shí)現(xiàn),因?yàn)橘Y源調(diào)度必然混亂。
2、假設(shè)TEE掛掉,則等于業(yè)務(wù)組此刻提交的任務(wù)均失敗,容災(zāi)機(jī)制需要建立。
到了這一步,很多小伙伴可能覺(jué)著一陣頭大,分布式不是大數(shù)據(jù)的東西嗎?不是的,不是大數(shù)據(jù)就不能分布式部署嗎?就不能有主從節(jié)點(diǎn)嗎?就不能有注冊(cè)中心嗎?要跨過(guò)內(nèi)心的固有思想,我們往下看。

設(shè)計(jì)說(shuō)明:
1、需要先將TEE項(xiàng)目做一下代碼分解,將管理調(diào)度模塊與任務(wù)執(zhí)行模塊拆解開(kāi)了。消耗性能和線(xiàn)程較高的是任務(wù)執(zhí)行模塊,定義為T(mén)EE執(zhí)行節(jié)點(diǎn)。消耗性能和線(xiàn)程較低,卻需要參數(shù)校驗(yàn)、任務(wù)封裝、資源調(diào)度、隊(duì)列管理的是管理調(diào)度模塊,定義為T(mén)EE管理節(jié)點(diǎn)。
2、TEE執(zhí)行節(jié)點(diǎn)可以多實(shí)例,形成節(jié)點(diǎn)池。管理節(jié)點(diǎn)可以考慮做成共享任務(wù)隊(duì)列的管理池。這里有個(gè)難點(diǎn),如何共享任務(wù)隊(duì)列。建議使用zookeeper或者緩存方式,但是不管哪種方式都要注意使用集群,避免單點(diǎn)故障導(dǎo)致隊(duì)列數(shù)據(jù)丟失。
3、關(guān)于注冊(cè)中心,可以使用開(kāi)源組件,nacos、zookeeper都可以。在該架構(gòu)設(shè)計(jì)中,其實(shí)注冊(cè)中心并沒(méi)有太多功能,如果你對(duì)自己有信心,可以嘗試自己寫(xiě)一個(gè)注冊(cè)中心,核心功能就是服務(wù)注冊(cè)與心跳檢測(cè)。可以用netty架構(gòu)做一做,提高一下自己的代碼能力。

4、在管理池的調(diào)用方面,增加網(wǎng)關(guān)代理,可以使用nginx、konga等。主要功能是業(yè)務(wù)端調(diào)用的時(shí)候,隨機(jī)打到管理節(jié)點(diǎn)上,就算一個(gè)管理節(jié)點(diǎn)掛了,也不會(huì)影響使用,保證了生產(chǎn)線(xiàn)的穩(wěn)定。
小結(jié):
分布式架構(gòu),主從節(jié)點(diǎn)模式也好、哨兵模式也好、選舉模式也好,按照自己的業(yè)務(wù)需求選擇最適合自己的。不是大數(shù)據(jù)才有分布式,它是一種設(shè)計(jì)思想,要知道開(kāi)發(fā)大數(shù)據(jù)組件的大佬們,也是一行行java寫(xiě)出來(lái)的。大佬們可以,為什么你不可以呢?
代碼設(shè)計(jì)
在著手開(kāi)發(fā)該系統(tǒng)的時(shí)候,我給大家一些代碼開(kāi)發(fā)的建議:
1、定時(shí)任務(wù)的實(shí)現(xiàn),從最簡(jiǎn)單的while死循環(huán)加sleep,到定時(shí)線(xiàn)程池,或者springboot的@Scheduled注解,都可以實(shí)現(xiàn)。我在這里推薦一下時(shí)間輪算法TimeWheel,有興趣的可以去了解一下。
2、異步消息處理,如果你只是想在項(xiàng)目?jī)?nèi)部使用消息總線(xiàn),推薦使用guava包內(nèi)的EventBus。按照消息的數(shù)量級(jí),考慮使用RabbitMQ或者Kafka作為消息中間件。
3、任務(wù)執(zhí)行,推薦使用CompletableFuture進(jìn)行異步非阻塞任務(wù)編程。
4、在資源的使用中,可能存在多種協(xié)議類(lèi)型http、ws、tcp等。所以代碼設(shè)計(jì)中,盡可能提供完整全面的協(xié)議工具類(lèi)。
總結(jié)
最近和一個(gè)同事閑聊的時(shí)候,他和我說(shuō)了說(shuō)最近面試高級(jí)研發(fā)的情況??偨Y(jié)一下,現(xiàn)在想招一個(gè)做過(guò)高并發(fā)場(chǎng)景的太難了,大部分人選只做業(yè)務(wù)相關(guān)。這讓我想到了十年前,我剛工作的時(shí)候。那時(shí)候沒(méi)有那么多框架,大部分功能需要看很多資料研究底層的原理與算法。隨著軟件行業(yè)的日益成熟,從以前拿著谷歌翻譯看國(guó)外的組建說(shuō)明,到從阿里云直接對(duì)接功能,軟件研發(fā)的成本和時(shí)間也在大大縮短。漸漸失去了研究分析的動(dòng)力,框架什么都有為什么要抓破腦袋自己寫(xiě)。
怎么成長(zhǎng)?怎么進(jìn)步?
上面給出的架構(gòu)圖,看上去都挺好理解。但真要自己去代碼實(shí)現(xiàn),中間各個(gè)環(huán)節(jié)出現(xiàn)的問(wèn)題真的好解決嗎?冰凍三尺,非一日之寒。沒(méi)有日積月累的學(xué)習(xí),是很難成功的。不要懼怕那些你看上去遙遠(yuǎn)的東西,獲取你的幾個(gè)晚上的學(xué)習(xí),它就成了你最趁手的武器。對(duì)學(xué)習(xí)而言,難的永遠(yuǎn)不是過(guò)程,而是踏出第一步。

高并發(fā)任務(wù)執(zhí)行架構(gòu)中,有一個(gè)模塊看上去很不起眼,但是在你研發(fā)的過(guò)程就會(huì)發(fā)現(xiàn)他會(huì)給你制造大麻煩-資源調(diào)度。以后有時(shí)間我會(huì)單獨(dú)做一篇關(guān)于資源調(diào)度的架構(gòu)設(shè)計(jì),與大家說(shuō)道說(shuō)道里面的坑。
最后說(shuō)一句:為什么不ban猛犸?

到此這篇關(guān)于Java 高并發(fā)編程之最實(shí)用的任務(wù)執(zhí)行架構(gòu)設(shè)計(jì)建議收藏的文章就介紹到這了,更多相關(guān)Java 高并發(fā)編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring kafka框架中@KafkaListener 注解解讀和使用案例
Kafka 目前主要作為一個(gè)分布式的發(fā)布訂閱式的消息系統(tǒng)使用,也是目前最流行的消息隊(duì)列系統(tǒng)之一,這篇文章主要介紹了kafka @KafkaListener 注解解讀,需要的朋友可以參考下2023-02-02
Java并發(fā)容器ConcurrentLinkedQueue解析
這篇文章主要介紹了Java并發(fā)容器ConcurrentLinkedQueue解析,2023-12-12
Java 使用Docker時(shí)經(jīng)常遇到的五個(gè)問(wèn)題
這篇文章主要介紹了Java 使用Docker時(shí)經(jīng)常遇到的五個(gè)問(wèn)題的相關(guān)資料,需要的朋友可以參考下2016-10-10
JAVA錯(cuò)誤類(lèi)結(jié)果類(lèi)和分頁(yè)結(jié)果類(lèi)代碼詳解
這篇文章主要介紹了JAVA錯(cuò)誤類(lèi)結(jié)果類(lèi)和分頁(yè)結(jié)果類(lèi)代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
基于Mybatis Plus實(shí)現(xiàn)多表分頁(yè)查詢(xún)的示例代碼
這篇文章主要介紹了基于Mybatis Plus實(shí)現(xiàn)多表分頁(yè)查詢(xún)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
JSch教程使用sftp協(xié)議實(shí)現(xiàn)服務(wù)器文件載操作
這篇文章主要為大家介紹了JSch如何使用sftp協(xié)議實(shí)現(xiàn)服務(wù)器文件上傳下載操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
解決feignclient調(diào)用服務(wù),傳遞的中文數(shù)據(jù)成???問(wèn)題
這篇文章主要介紹了解決feignclient調(diào)用服務(wù),傳遞的中文數(shù)據(jù)成???問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
利用Redis實(shí)現(xiàn)延時(shí)處理的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于利用Redis實(shí)現(xiàn)延時(shí)處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03

