SpringBoot項目保證接口冪等的五種方法!

1. 冪等概述

1.1 深入理解冪等性

在計算機領域中,冪等(Idempotence)是指任意一個操作的多次執行總是能獲得相同的結果,不會對系統狀態產生額外影響。在Java后端開發中,冪等性的實現通常通過確保方法或服務調用的結果具有確定性,無論調用次數如何,結果都是可預期的。

上面的定義是目前大多數文章和書籍對冪等的描述,然而,在實際的互聯網服務開發中,冪等性的理論定義與業務邏輯間的沖突是常見的。

例如,考慮查詢操作,當A系統調用B系統的查詢接口時,如果首次調用由于B系統中的程序錯誤而導致業務邏輯失敗,即使在程序修復后系統A重新使用相同參數進行重試,B系統可能仍然返回相同的失敗響應。盡管這符合冪等性的定義,卻與實際業務邏輯不符。同樣,以訂單支付為例,首次調用由于賬戶余額不足而返回“余額不足”提示,用戶充值后再次使用相同參數發起支付請求,服務仍然返回“余額不足”響應,也符合冪等性的定義,但同樣不符合業務邏輯。

因此,在實現冪等性方案時,應該遵循冪等性方案的目標,而不僅僅是嚴格遵循冪等性的定義。尤其是涉及寫操作的服務,應當更關注防止重復請求帶來的不良副作用,例如重復扣款或退款。

 

歡迎加入蘇三的星球,你將獲得:商城微服務實戰、AI開發項目課程、蘇三AI項目、秒殺系統實戰、商城系統實戰、秒殺系統實戰、代碼生成工具、系統設計、性能優化、技術選型、底層原理、Spring源碼解讀、工作經驗分享、痛點問題、面試八股文等多個優質專欄。

  • 我的技術成長之路

  • 這5個項目,yyds

還有1V1修改簡歷、技術答疑、職業規劃、送書活動、技術交流。

1.2 冪等性的必要性

在微服務和分布式架構中,一個請求可能需要多個服務協作才能完成。在這個過程中,網絡抖動、系統運行異常等不確定因素使得請求的成功率不可能達到100%,一旦發生失敗或未知異常,最常見的處理方式就是重試,而重試必然會導致重復請求問題。

冪等設計主要是為了處理重復請求而生的,好的冪等方案可以保證重復請求獲得預期結果,而不產生副作用。?在實際開發中,以下場景會產生重復請求:

  • 用戶不可靠:用戶通過客戶端發起請求,由于手抖或有意重復點擊,很容易造成導致極短時間內發起多次重復請求。

  • 網絡不可靠:網絡抖動、網關內部抖動有可能觸發重試機制,這個在使用消息隊列投遞消息時經常會遇到。

  • 服務不可靠:在需要保證數據一致性的場景中,如果調用下游服務超時,在無法確認執行結果的情況下,常用的處理方法是重試。

在我的SpringCloud微服務專欄《使用RocketMQ實現分布式事務》一文中就遺留了個冪等導致的bug,由于消費端沒做冪等處理,所以在整個消息鏈路中,如果broker沒有收到消費者發送的ack響應就會發起重試,從而產生數據一致性問題。

1.3 冪等與并發的關系

在具有并發寫操作的場景下,通常需要考慮冪等問題。例如,當用戶在極短時間內多次提交表單或者使用特殊手段同時提交多個表單時,這就是典型的并發場景,需要進行冪等性處理。為了防止重復請求被執行,服務端需要實施冪等性控制,以避免產生不符合預期的結果。

雖然并發場景大都存在冪等問題,但冪等問題卻并非并發場景所特有。冪等設計是為了識別并處理重復請求,而并發僅僅是重復請求的一種特殊情況。?事實上,只要重復請求涉及寫操作,無論是否并發,都需要做好冪等處理。舉個例子,用戶在pc端同時開了兩個窗口,間隔10分鐘分別提交表單,所有參數完全相同,這顯然不屬于并發,但仍需要進行冪等處理。

在互聯網領域,并發處理與冪等性問題緊密相關,這也導致了一些人認為解決冪等性就是解決高并發的問題。

2. 冪等號的設計

冪等性設計的目的是確保即使在多次接收相同請求的情況下,也只執行一次操作,防止重復處理。要實現這一點,通常需要事先約定一個具有唯一性的標識符,如Token或業務流水號,我們稱之為冪等號(Idempotency Key)。

冪等號有三個關鍵特性:唯一性、不變性和傳遞性。

唯一性確保每個請求都能被準確識別,不變性保證在請求處理期間冪等號保持不變,傳遞性則確保在多系統處理同一請求時,冪等號能夠被傳遞和保持。

冪等號通常有兩種設計方式:

  1. 非業務冪等號:通過唯一標識符(如UUID、時間戳或業務流水號)在調用方和被調用方之間明確實現冪等性。由于非業務冪等號難以通過業務上下文追溯,因此調用雙方都必須將其持久化,從而保證請求與冪等號的關系有跡可循。

    例如,在DailyMart案例中,訂單服務在調用庫存服務時會傳遞訂單流水號作為冪等號,以便在多次請求時識別重復操作。

  2. 業務冪等號:由業務元素組合構成的冪等號,如“用戶ID+活動ID”。使用此方法時,調用方無需單獨持久化冪等號,被調用方可以根據請求參數和業務上下文直接獲取并組合這些參數。例如,通過設置“用戶ID”和“活動ID”的聯合唯一索引來實現冪等性。

3. 冪等的實現方案

冪等性的實現關鍵在于確保相同的請求僅被處理一次,這通常可以通過設置唯一性約束和檢查來實現。實踐中有六種常見的方案:唯一索引、Token機制、悲觀鎖、樂觀鎖、分布式鎖和狀態機。

3.1 唯一索引方案機制

唯一索引方案依賴于數據庫表中不允許存在具有相同索引值的重復行。這種策略在關系型數據庫中廣泛支持,并且能有效利用唯一性約束來確保冪等性。在高并發場景中,唯一索引能保證當多個線程嘗試同時插入相同記錄時,只有一個線程能成功執行,而其他線程將會因違反唯一性約束而拋出異常。

通常,業務流水表的建立是基于以下核心字段:

  • id(bigint 類型):作為主鍵,唯一標識每條記錄。

  • gmt_create(datetime 類型):記錄的創建時間。

  • gmt_modified(datetime 類型):記錄的最后修改時間。

  • user_id(varchar(32) 類型):用戶ID,這個字段也可以作為分表的依據。

  • out_biz_no(varchar(64) 類型):外部業務流水號,即調用方的冪等號。

  • biz_no(varchar(64) 類型):內部業務流水號,用于系統內部追蹤。

  • status(char(1) 類型):記錄執行狀態。

在這種設計中,user_idout_biz_no通常會組合成一個聯合索引,這樣做能有效避免在并發情況下的數據重復插入問題,從而保障了業務操作的冪等性。

3.2 Token機制

Token機制是用于防止客戶端重復提交的一種特殊機制,特別適用于客戶端創建訂單等提交表單場景。其執行流程如下:

?1)當用戶訪問表單頁面時,客戶端請求服務端接口以獲取唯一的Token(可以是UUID或全局ID),服務端生成的Token會被存儲在Redis或數據庫中。

2)用戶首次提交表單時,將Token與表單一起發送至服務端,服務端會驗證Token的存在性,如果Token存在,則執行業務邏輯,并在完成后銷毀Token。

3)用戶再次提交表單時,同樣攜帶Token一起發送至服務端。但由于Token已被銷毀,服務端無法找到對應的Token,從而拒絕重復提交請求。

3.3 悲觀鎖機制

悲觀鎖依賴數據庫提供的鎖機制來實現,整個數據處理過程中,數據處于鎖定狀態,并與事務機制配合,能夠有效實現業務冪等性。操作示例如下:

// 1. 開啟事務
begin;// 2. 基于冪等號查詢
record = select * from tbl_xxx where out_biz_no =?'xxx'for?update;// 3. 根據狀態進行決策
if(record.getStatus() != 預期狀態){return;
}// 4. 更新記錄
update tbl_xxx set status =?'目標狀態'?where out_biz_no =?'xxx';// 5. 提交事務
commit;

悲觀鎖主要適用于更新場景,通過串行化請求處理來確保冪等性,但需要小心使用,因為在并發場景下,重復請求可能會導致線程長時間處于等待狀態,浪費資源且降低性能。

3.4 樂觀鎖機制

樂觀鎖主要依靠"帶條件更新"(update with condition)來確保多次外部請求的一致性。在系統設計中,可以在數據表中添加版本號字段,用于標識當前數據的版本。每次對該數據表的記錄進行更新時,都需要提供上一次更新的版本號,示例操作如下:

//1. 取出要更新的對象,帶有版本versoin
select?*?from?tablename?where?id?= xxx//2.?更新數據
update?tableName?set?sq = sq-#{quantity},version = #{version}+1 where id = xxx and version=#{version}

樂觀鎖主要適用于更新場景,確保多次更新不會影響結果的一致性。

3.5 分布式鎖機制

分布式鎖與悲觀鎖本質上相似,都通過串行化請求處理來實現冪等性。與悲觀鎖不同的是,分布式鎖更輕量。在系統接收請求后,首先嘗試獲取分布式鎖。如果成功獲取鎖,則執行業務邏輯;如果獲取失敗,則立即拒絕請求。

分布式鎖的核心是識別重復請求,實現串行化處理。但要注意,獲取鎖成功后,業務邏輯的執行并沒有可靠保證。因此,在實際應用中,分布式鎖需要結合事務機制和重試機制,以形成完整的冪等性解決方案。

3.6 狀態機機制

在許多業務單據中,存在有限數量的狀態,并且這些狀態之間的流轉順序是固定的。如果狀態已經處于下一個狀態,那么再次應用上一個狀態的變更邏輯是不會產生任何效果的,這就確保了有限狀態機的冪等性。

例如,庫存狀態通常包括"預扣中"、"扣減中"、"占用中"和"已釋放"等狀態。如果系統重復調用扣減接口,而庫存狀態已經是"扣減中",則可以直接返回結果。

狀態機可以與樂觀鎖機制結合使用,示例操作如下:

update?tableName?set?sq=sq-#{quantity},status=#{udpate_status} where id =#{id} and status=#{status}

3.7 小結

上面介紹了冪等方式的6種實現方案并簡單介紹了每周方案的適合場景,這些方案的技術路線可以總結成三條:唯一索引、唯一數據、狀態機約束。

唯一索引是指數據庫唯一索引,唯一索引大部分是基于業務流水表建立,也可單獨建表實現;唯一數據是指悲觀鎖、樂觀鎖、分布式鎖等機制;狀態機約束,對于存在狀態流轉的業務,通過狀態機的流轉約束,可以實現有限狀態機的冪等。

需要注意的是:在實際開發中,這些方案單獨使用很難奏效,比如悲觀鎖、分布式鎖只是將請求串行化處理,對于出現異常后的重試并沒有什么抵御能力,需要搭配唯一索引才能形成完整的冪等方案。而在唯一索引方案中也還需要搭配事務機制才能生效。所以需要結合具體的業務場景靈活運用上面的實現方案。

以上介紹了六種實現冪等性的方式,每種方式的適用場景和關鍵信息。這些方式可以總結為三個技術路線:唯一索引、唯一數據和狀態機約束。

需要注意的是,在實際開發中,單獨使用這些方式可能無法完全解決問題。例如,悲觀鎖和分布式鎖只將請求串行化處理,沒有處理異常后的重試,因此需要結合唯一索引來實現完整的冪等性解決方案。同樣,因此,在實際應用中,需要根

以上介紹了六種實現冪等性的方式,并簡要介紹了每種方式適用的場景和關鍵信息。這些方式可以總結為三個技術路線:唯一索引、唯一數據和狀態機約束。

  • 唯一索引指的是數據庫的唯一索引,通常基于業務流水表創建,也可以單獨創建表來實現。

  • 唯一數據包括悲觀鎖、樂觀鎖、分布式鎖等機制。

  • 狀態機約束適用于具有狀態流轉的業務,通過狀態機的流轉約束,可以實現有限狀態機的冪等性。

然而,需要注意的是,在實際開發中,單獨使用這些方法往往效果有限。?例如,悲觀鎖和分布式鎖只是將請求串行處理,對于異常情況的重試并沒有足夠的防御能力,因此需要結合唯一索引來實現完整的冪等性解決方案。同樣,唯一索引方案也需要與事務機制結合使用。因此,在實際應用中,需要根據具體的業務場景靈活選擇、合理的運用上述實現方法。

4. 代碼實現

在Dailymart項目中,實現了除悲觀鎖以外的五種冪等方案。為了方便使用,我將分布式鎖機制和Token機制封裝在一個單獨的冪等組件dailymart-idempotent-spring-boot-starter中。

在業務模塊中,只需在pom文件中引入依賴即可使用封裝好的冪等功能。

<dependency><groupId>com.jianzh5</groupId><artifactId>dailymart-idempotent-spring-boot-starter</artifactId><version>${project.version}</version>
</dependency>

冪等組件的核心是利用Spring的AOP機制實現。在使用時,只需在需要實現冪等的方法上添加自定義注解@Idempotent,并指定冪等方案IdempotentTypeEnum

?

在自定義冪等組件中,分布式鎖方案依賴于Redis。因此,在SpringBoot配置文件中需要加上Redis的相關配置,并添加一些自定義配置,如Redis key的自定義前綴以及分布式鎖key的前綴。

spring:data:redis:host:?xxx.xx.xx.xxport:?29359
dailymart:cache:redis:prefix:?"inventory:"idempotent:token:prefix:?"token-"timeout:?30000

接下來,結合具體應用場景,演示在DailyMart中如何實現這些冪等方案。

4.1 基于唯一索引實現

用戶下單時需要調用庫存預扣接口,在這種新增場景下,可以使用唯一索引結合事務機制實現冪等方案。

1、在扣減流水表中給業務流水字段transactionId加上唯一索引。

2、在Service層讓庫存扣減和庫存修改在同一個事務中,確保出現重復請求時事務回滾,從而保證冪等性。

這部分代碼已在上篇文章中展示,源碼位于com/jianzh5/dailymart/module/inventory/application/service/impl/InventoryServiceImpl.java

4.2 基于樂觀鎖實現

用戶付款時會調用庫存扣減接口,這種更新場景可以使用樂觀鎖機制來實現冪等方案。在Dailymart中,有兩種實現方式。

4.2.1 基于原生SQL實現
public?interface?InventoryItemMapper?extends?BaseMapper<InventoryItemDO>?{/*** 基于樂觀鎖實現更新*?@param?inventoryItemDO 庫存實體*/@Update("UPDATE inventory_item SET sellable_quantity = #{sellableQuantity},withholding_quantity = #{withholdingQuantity}, occupy_quantity = #{occupyQuantity} ,version = #{version} + 1 , update_time = NOW() WHERE id = #{id} AND version = #{version} ")void?updateByVersion(InventoryItemDO inventoryItemDO);
}
4.2.2 使用mybatis-plus提供的樂觀鎖插件

1、在DO對象中使用@Version注解對樂觀鎖字段進行標注。

public?class?InventoryItemDO?extends?BaseDO?{...@Versionprivate?Integer version;
}

2、在mybatis-plus的配置類中添加樂觀鎖插件

public?class?DailyMartDsAutoConfiguration?{ ? ?/*** 設置mybatis-plus攔截器* 1. 分頁攔截器* 2. 樂觀鎖攔截器*/@Beanpublic?MybatisPlusInterceptor?mybatisPlusInterceptor()?{MybatisPlusInterceptor interceptor =?new?MybatisPlusInterceptor();//分頁interceptor.addInnerInterceptor(new?PaginationInnerInterceptor(DbType.MYSQL));// 樂觀鎖interceptor.addInnerInterceptor(new?OptimisticLockerInnerInterceptor());return?interceptor;
}

這樣,當使用inventoryItemMapper.updateById(inventoryItemDO);方法時會自動實現樂觀鎖。

4.3 基于狀態機實現

用戶退貨時需要調用庫存釋放接口,可以基于有限狀態機來實現冪等。

@Override
@Transactional
public?void?releaseInventory(Long transactionId)?{...//如果已經是釋放狀態直接返回結果if(inventoryRecord.getState() == InventoryRecordStateEnum.RELEASE.code()){return;}...
}

單一的狀態機機制不能很好地保證冪等性,因此需要結合樂觀鎖機制才更有效。

4.3 基于Token實現

用戶在創建訂單時需要調用后臺接口提交表單,像這種客戶端提交表單的操作就很適合使用token機制。

1、在客戶端進入頁面時調用冪等組件提供的/token方法,后端自動生成token并存儲到Redis中。

@Override
public?String?createToken()?{String token = Optional.ofNullable(Strings.emptyToNull(idempotentProperties.getPrefix())).orElse(TOKEN_PREFIX_KEY) + UUID.randomUUID();log.info("Generated Idempotency Key is: {}", token);distributedCache.put(token,?"", Optional.ofNullable(idempotentProperties.getTimeout()).orElse(TOKEN_EXPIRED_TIME));return?token;
}

2、在創建訂單接口加上自定義冪等注解,指定冪等類型為Token機制。

@PostMapping("/api/order/create")
@Idempotent(type = IdempotentTypeEnum.TOKEN,message =?"訂單正在創建,請勿重復提交"
)
public?void?create(@RequestBody OrderDTO orderDTO)?{orderService.save(orderDTO);
}

Token機制也需要結合唯一索引才能形成完整的冪等方案。

4.3 基于分布式鎖實現

使用分布式鎖冪等方案很簡單,在方法上加上冪等注解即可。有兩種使用方式:

1、指定type為IdempotentTypeEnum.PARAM,此時冪等組件會將整個表單的參數做MD5摘要后作為分布式鎖的key

@Idempotent(type = IdempotentTypeEnum.PARAM,message =?"訂單正在創建,請勿重復提交"
)
@PostMapping("/api/order/create") ?
public?void?create(@RequestBody OrderDTO orderDTO)?{ ?orderService.create(orderDTO); ?
}

2、指定type為IdempotentTypeEnum.SpEL,此時冪等組件會根據key的值選取參數作為分布式鎖的key,冪等key可以使用SpEL表達式選擇參數中的字段。

@Idempotent( ?key =?"#lockRequest.transactionId", ?type = IdempotentTypeEnum.SpEL ?
)
@PostMapping("/api/order/update") ?
public?void?update(@RequestBody OrderDTO orderDTO)?{ ?orderService.update(orderDTO); ?
}

通過以上實現,Dailymart項目成功應用了多種冪等性方案,確保了系統的可靠性和穩定性。

5. 小結

本文詳細介紹了在分布式系統中冪等性實現方案,同時著重講解了冪等和并發之間的區別。

一般而言,并發都會伴隨冪等,而冪等又并非并發獨有。

文章中提供了多種關于冪等的實現方案,不過需要記住,單一使用某種冪等方案往往很難奏效,需要組合多種方式才能形成完整的解決方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88720.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL新手入門詳細教程和應用實例

SQL(Structured Query Language)是用于管理和操作關系型數據庫的標準語言。它允許你創建、查詢、更新和刪除數據。本教程將從基礎概念開始,逐步引導你上手SQL,并提供詳細的應用實例。教程基于標準SQL語法,實際使用時需根據數據庫系統(如MySQL、SQLite或PostgreSQL)調整。…

DVWA-LOW級-SQL手工注入漏洞測試(MySQL數據庫)+sqlmap自動化注入-小白必看(超詳細)

首次使用DVWA的靶場&#xff0c;咋們先從最低級別的LOW開始&#xff0c;因為之前玩過一下墨者學院&#xff0c;對sql注入有一點認識和理解&#xff0c;所以先從sql的盲注開始&#xff1b; 1、測試注入點是否存在sql注入的漏洞&#xff1b; &#xff08;1&#xff09;首先我們…

JAVA線程池詳解+學習筆記

1.線程池基礎概念線程池是一種資源復用技術&#xff0c;通過預先創建并管理一組線程&#xff0c;減少頻繁創建和銷毀線程的開銷。核心思想與數據庫連接池、字符串常量池類似&#xff0c;旨在提升系統性能。核心參數解析ThreadPoolExecutor構造函數包含7個關鍵參數&#xff1a;c…

數據分析庫 Pandas

對于Pandas的簡單認識和基本操作的練習一 介紹 Pandas 是一個開源的數據分析和數據處理庫&#xff0c;它是基于 Python 編程語言的庫。 Pandas 提供了易于使用的數據結構和數據分析工具&#xff0c;特別適用于處理結構化數據&#xff0c;如表格型數據&#xff08;類似于 Excel …

qt 中不要讓 lambda 槽函數捕獲信號源對象的共享指針

錯誤示例std::shared_ptr<QSerialPort> serial{new QSerialPort{}};QSerialPort::connect(serial.get(),&QSerialPort::readyRead,[serial](){QByteArray receive_data serial->readAll();std::cout.write(receive_data.data(), receive_data.size());});這會直接…

Solidity 合約的編寫-完整開發流程:從編譯、測試、部署到交互

&#x1f9f1; Solidity 合約開發全流程&#xff08;Foundry 版&#xff09;? 適合對象&#xff1a;已經能寫合約但不清楚如何測試、部署、交互的開發者? 工具鏈&#xff1a;Foundry&#xff08;forge, anvil, cast&#xff09;&#x1f4cc; 開發流程總覽1?? 初始化項目 2…

設計模式 - 面向對象原則:SOLID最佳實踐

文章目錄深入理解 SOLID&#xff1a;用對原則&#xff0c;別把簡單問題搞復雜SOLID 原則概覽1. 單一職責原則&#xff08;SRP&#xff09;2. 開閉原則&#xff08;OCP&#xff09;3. 里氏替換原則&#xff08;LSP&#xff09;4. 接口隔離原則&#xff08;ISP&#xff09;5. 依賴…

Vue 3 中父組件內兩個子組件相互傳參的幾種方法

方法一&#xff1a;通過父組件中轉&#xff08;Props Emits&#xff09;<!-- ParentComponent.vue --> <template><ChildA :message-from-b"messageFromB" send-to-b"handleSendToB" /><ChildB :message-from-a"messageFromA&q…

三子棋游戲設計與實現(C 語言版)

一、需求分析目標&#xff1a;實現一個簡單的人機對戰三子棋&#xff0c;支持以下功能&#xff1a;初始化空棋盤&#xff0c;清晰展示落子狀態。玩家通過坐標落子&#xff08;X 代表玩家&#xff09;&#xff0c;電腦隨機落子&#xff08;O 代表電腦&#xff09;。實時判斷勝負…

GD32 CAN1和TIMER0同時開啟問題

背景&#xff1a;今天在一個項目調試的時候發現了一些問題&#xff0c;由此貼記錄一下問題解決的過程。使用的芯片是GD32F305VE。使用到了CAN1和TIMER0。在使用這連個外設的時候發送了一些問題。單獨使用CAN1。功能正常。單獨使用TIMER0。配置為輸出模式。功能正常。但是當兩個…

劍指offer56_數組中唯一只出現一次的數字

數組中唯一只出現一次的數字在一個數組中除了一個數字只出現一次之外&#xff0c;其他數字都出現了三次。 請找出那個只出現一次的數字。 你可以假設滿足條件的數字一定存在。 思考題&#xff1a; 如果要求只使用 O(n) 的時間和額外 O(1) 的空間&#xff0c;該怎么做呢&#xf…

從語音識別到智能助手:Voice Agent 的技術進化與交互變革丨Voice Agent 學習筆記

From Research AI&#xff1a; 最近看到 Andrew Ng 的一句話讓我印象深刻&#xff1a;“While some things in AI are overhyped, voice applications seem underhyped right now.”&#xff08;盡管 AI 中有些領域被過度炒作&#xff0c;語音應用卻似乎被低估了&#xff09;。…

什么是Jaccard 相似度(Jaccard Similarity)

文章目錄? 定義&#xff1a;&#x1f4cc; 取值范圍&#xff1a;&#x1f50d; 舉例說明&#xff1a;&#x1f9e0; 應用場景&#xff1a;?? 局限性&#xff1a;&#x1f4a1; 擴展概念&#xff1a;Jaccard 相似度&#xff08;Jaccard Similarity&#xff09; 是一種用于衡量…

ragflow_多模態文檔解析與正文提取策略

多模態文檔解析與正文提取策略 RAGflow的文檔解析系統位于deepdoc/parser/目錄下,實現了對多種文檔格式的統一解析處理。該系統采用模塊化設計,針對不同文檔格式提供專門的解析器,并通過視覺識別技術增強解析能力。本文將深入探討RAGflow的文檔解析系統的設計原理、實現細節…

數據結構棧的實現(C語言)

棧的基本概念棧是一種特殊的線性存儲結構&#xff0c;是一種操作受到限制的線性表&#xff0c;特殊體現在兩個地方&#xff1a;1、元素進棧出棧的操作只能從同一端完成&#xff0c;另一端是封閉的&#xff0c;通常將數據進棧叫做入棧&#xff0c;壓棧等&#xff0c;出棧叫做彈棧…

【springboot】IDEA手動創建SpringBoot簡單工程(無插件)

大致步驟 創建Maven工程 引入依賴 提供啟動類 詳細教程 創建Maven工程 修改pom.xml文件 添加父節點 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.3</…

獨立開發第二周:構建、執行、規劃

一 第二周的獨立開發旅程落下帷幕。相較于第一周的適應&#xff0c;本周的核心詞是“聚焦”與“執行”。 目標非常明確&#xff1a;在產品開發上取得進展&#xff1b;在個人工作節奏上&#xff0c;將上周初步形成的框架進行實踐與固化。 同時&#xff0c;為至關重要的自媒體運營…

在YOLO-World中集成DeformConv、CBAM和Cross-Modal Attention模塊的技術報告

在YOLO-World中集成DeformConv、CBAM和Cross-Modal Attention模塊的技術報告 1. 引言 1.1 項目背景 目標檢測是計算機視覺領域的核心任務之一,而YOLO(You Only Look Once)系列算法因其出色的速度和精度平衡而廣受歡迎。YOLO-World是YOLO系列的最新發展,專注于開放詞匯目標…

從UI設計到數字孿生實戰應用:構建智慧金融的風險評估與預警平臺

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;傳統金融風控的 “滯后困境” 與數字孿生的破局之道金融風險的隱蔽性、突…

【Linux】權限相關指令

前言&#xff1a; 上兩篇文章我們講到了&#xff0c;關于Linux中的基礎指令。 【Linux】初見&#xff0c;基礎指令-CSDN博客【Linux】初見&#xff0c;基礎指令&#xff08;續&#xff09;-CSDN博客 本文我們來講Linux中關于權限中的一些指令 shell命令 Linux嚴格來說是一個操…