【6.1.2 漫畫分布式事務技術選型】

漫畫分布式事務技術選型

🎯 學習目標:掌握架構師核心技能——分布式事務技術選型與一致性解決方案,構建高可靠的分布式系統


🎭 第一章:分布式事務模式對比

🤔 2PC vs 3PC vs TCC vs Saga

想象分布式事務就像不同的團隊協作方式…

🎭 分布式事務協作模式:2PC (二階段提交):
┌─────────────────────────────────────┐
│        協調者 (Coordinator)          │
│              │                      │
│    ┌─────────┼─────────┐            │
│    ▼         ▼         ▼            │
│ 參與者A   參與者B   參與者C          │
│ (準備)    (準備)    (準備)           │
│    │         │         │            │
│    ▼         ▼         ▼            │
│ (提交)    (提交)    (提交)           │
│                                    │
│ 特點:                              │
│ ? 強一致性保證                      │
│ ? 阻塞性問題                        │
│ ? 單點故障風險                      │
│ ? 適用:小規模關鍵業務              │
└─────────────────────────────────────┘TCC (Try-Confirm-Cancel):
┌─────────────────────────────────────┐
│           業務活動管理器             │
│              │                      │
│    ┌─────────┼─────────┐            │
│    ▼         ▼         ▼            │
│ 服務A-Try 服務B-Try 服務C-Try       │
│ (資源預留) (資源預留) (資源預留)     │
│    │         │         │            │
│    ▼         ▼         ▼            │
│ Confirm   Confirm   Confirm         │
│ (確認)    (確認)    (確認)           │
│                                    │
│ 特點:                              │
│ ? 業務侵入性強                      │
│ ? 最終一致性                        │
│ ? 性能較好                          │
│ ? 適用:業務可拆分場景              │
└─────────────────────────────────────┘Saga (長事務):
┌─────────────────────────────────────┐
│          Saga編排器                  │
│              │                      │
│    T1 → T2 → T3 → T4 → T5           │
│    │    │    │    │    │            │
│   C1 ← C2 ← C3 ← C4 ← C5            │
│ (事務)              (補償)           │
│                                    │
│ 特點:                              │
│ ? 長事務友好                        │
│ ? 業務補償邏輯                      │
│ ? 最終一致性                        │
│ ? 適用:復雜業務流程                │
└─────────────────────────────────────┘

📊 分布式事務技術詳細對比

📊 分布式事務技術對比:┌─────────────┬─────────────┬─────────────┬─────────────┐
│    特性     │     2PC     │     TCC     │    Saga     │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 🔒 一致性   │    強一致    │   最終一致   │   最終一致   │
│ 🚀 性能     │     低      │     中      │     高      │
│ 🔧 復雜度   │    簡單     │     高      │     中      │
│ 📊 吞吐量   │     低      │     中      │     高      │
│ 🛡? 可靠性   │    中等     │     高      │     高      │
│ 💻 業務侵入 │     小      │     大      │     中      │
│ 🌐 適用場景 │  關鍵業務    │  核心交易    │  復雜流程   │
│ 🎯 推薦度   │     低      │     高      │     高      │
└─────────────┴─────────────┴─────────────┴─────────────┘技術選型建議:
🎯 銀行轉賬系統 → TCC (資金安全)
🎯 電商下單流程 → Saga (流程復雜)
🎯 庫存扣減場景 → TCC (原子操作)
🎯 數據同步任務 → Saga (長時間運行)
🎯 支付系統 → TCC (強一致性要求)

🎯 分布式事務選型決策樹

🎯 分布式事務選型流程:開始選型│┌────▼────┐│一致性要求│└────┬────┘│┌──────────────┼──────────────┐▼              ▼              ▼強一致性       最終一致性      高性能要求│              │              │┌────▼────┐    ┌────▼────┐    ┌────▼────┐│關鍵業務  │    │復雜流程  │    │高并發   │└────┬────┘    └────┬────┘    └────┬────┘│              │              │▼              ▼              ▼XA/2PC事務      Saga模式        異步消息(小規模場景)    (長事務場景)     (最終一致)重要業務場景選型:
┌─────────────────┬─────────────┬─────────────┐
│   業務場景       │  推薦方案    │   備選方案   │
├─────────────────┼─────────────┼─────────────┤
│ 銀行轉賬         │    TCC      │    XA       │
│ 電商下單         │   Saga      │   本地消息表 │
│ 庫存扣減         │    TCC      │   分布式鎖   │
│ 訂單支付         │    TCC      │    2PC      │
│ 數據同步         │   Saga      │   消息隊列   │
│ 批量處理         │   Saga      │   狀態機    │
└─────────────────┴─────────────┴─────────────┘

🛠? 第二章:Seata分布式事務框架

🏗? Seata架構與模式

// 🛠? Seata分布式事務實戰/*** Seata配置中心*/
@Configuration
@EnableAutoDataSourceProxy
public class SeataConfig {/*** AT模式數據源代理*/@Bean@Primarypublic DataSourceProxy dataSourceProxy(DataSource dataSource) {return new DataSourceProxy(dataSource);}/*** TCC模式業務資源管理器*/@Beanpublic TccTransactionManager tccTransactionManager() {return new TccTransactionManager();}/*** Saga狀態機配置*/@Beanpublic StateMachineEngine stateMachineEngine() {StateMachineEngineBuilder builder = StateMachineEngineBuilder.newBuilder();builder.setDataSource(dataSource()).setTransactionManager(platformTransactionManager()).setApplicationContext(applicationContext);return builder.build();}
}/*** AT模式 - 自動補償*/
@Service
@Slf4j
public class OrderServiceAT {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate AccountServiceClient accountServiceClient;@Autowiredprivate ProductServiceClient productServiceClient;/*** 創建訂單 - AT模式全局事務*/@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)public Order createOrder(CreateOrderRequest request) {log.info("開始創建訂單: userId={}", request.getUserId());try {// 1. 創建訂單記錄Order order = new Order();order.setUserId(request.getUserId());order.setProductId(request.getProductId());order.setQuantity(request.getQuantity());order.setAmount(request.getAmount());order.setStatus(OrderStatus.PENDING);order.setCreateTime(LocalDateTime.now());order = orderRepository.save(order);log.info("訂單創建成功: orderId={}", order.getId());// 2. 扣減賬戶余額accountServiceClient.deductBalance(request.getUserId(), request.getAmount());log.info("賬戶扣款成功: userId={}, amount={}", request.getUserId(), request.getAmount());// 3. 扣減商品庫存productServiceClient.reduceStock(request.getProductId(), request.getQuantity());log.info("庫存扣減成功: productId={}, quantity={}", request.getProductId(), request.getQuantity());// 4. 更新訂單狀態order.setStatus(OrderStatus.SUCCESS);orderRepository.save(order);log.info("訂單處理完成: orderId={}", order.getId());return order;} catch (Exception e) {log.error("訂單創建失敗: userId={}", request.getUserId(), e);throw new OrderException("訂單創建失敗: " + e.getMessage(), e);}}
}/*** TCC模式 - 手動補償*/
@LocalTCC
@Service
@Slf4j
public class AccountServiceTCC {@Autowiredprivate AccountRepository accountRepository;@Autowiredprivate AccountFreezeRepository freezeRepository;/*** Try階段 - 凍結資金*/@TwoPhaseBusinessAction(name = "deductBalance",commitMethod = "confirmDeduct",rollbackMethod = "cancelDeduct")public boolean deductBalance(BusinessActionContext context,@BusinessActionContextParameter("userId") Long userId,@BusinessActionContextParameter("amount") BigDecimal amount) {String xid = context.getXid();log.info("TCC Try階段 - 凍結資金: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 檢查賬戶余額Account account = accountRepository.findByUserId(userId);if (account == null) {throw new AccountException("賬戶不存在");}if (account.getBalance().compareTo(amount) < 0) {throw new InsufficientBalanceException("余額不足");}// 2. 凍結資金AccountFreeze freeze = new AccountFreeze();freeze.setXid(xid);freeze.setUserId(userId);freeze.setAmount(amount);freeze.setStatus(FreezeStatus.TRYING);freeze.setCreateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 扣減可用余額account.setBalance(account.getBalance().subtract(amount));account.setFrozenAmount(account.getFrozenAmount().add(amount));accountRepository.save(account);log.info("資金凍結成功: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("資金凍結失敗: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}/*** Confirm階段 - 確認扣款*/public boolean confirmDeduct(BusinessActionContext context) {String xid = context.getXid();Long userId = (Long) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");log.info("TCC Confirm階段 - 確認扣款: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 查找凍結記錄AccountFreeze freeze = freezeRepository.findByXid(xid);if (freeze == null) {log.warn("凍結記錄不存在: xid={}", xid);return true; // 冪等性處理}if (freeze.getStatus() == FreezeStatus.CONFIRMED) {log.warn("重復確認: xid={}", xid);return true; // 冪等性處理}// 2. 確認扣款freeze.setStatus(FreezeStatus.CONFIRMED);freeze.setUpdateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 減少凍結金額Account account = accountRepository.findByUserId(userId);account.setFrozenAmount(account.getFrozenAmount().subtract(amount));accountRepository.save(account);log.info("扣款確認完成: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("扣款確認失敗: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}/*** Cancel階段 - 取消扣款*/public boolean cancelDeduct(BusinessActionContext context) {String xid = context.getXid();Long userId = (Long) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");log.info("TCC Cancel階段 - 取消扣款: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 查找凍結記錄AccountFreeze freeze = freezeRepository.findByXid(xid);if (freeze == null) {log.warn("凍結記錄不存在: xid={}", xid);return true; // 冪等性處理}if (freeze.getStatus() == FreezeStatus.CANCELLED) {log.warn("重復取消: xid={}", xid);return true; // 冪等性處理}// 2. 取消凍結freeze.setStatus(FreezeStatus.CANCELLED);freeze.setUpdateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 恢復資金Account account = accountRepository.findByUserId(userId);account.setBalance(account.getBalance().add(amount));account.setFrozenAmount(account.getFrozenAmount().subtract(amount));accountRepository.save(account);log.info("扣款取消完成: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("扣款取消失敗: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}
}/*** Saga模式 - 狀態機編排*/
@Component
@Slf4j
public class OrderSagaService {@Autowiredprivate StateMachineEngine stateMachineEngine;/*** 執行訂單處理Saga*/public void processOrderSaga(CreateOrderRequest request) {log.info("開始執行訂單Saga: userId={}", request.getUserId());try {// 創建狀態機實例StateMachineInstance instance = stateMachineEngine.startAsync("orderProcessSaga",UUID.randomUUID().toString(),createSagaContext(request));log.info("訂單Saga啟動成功: instanceId={}", instance.getId());} catch (Exception e) {log.error("訂單Saga啟動失敗: userId={}", request.getUserId(), e);throw new SagaException("Saga執行失敗: " + e.getMessage(), e);}}private Map<String, Object> createSagaContext(CreateOrderRequest request) {Map<String, Object> context = new HashMap<>();context.put("userId", request.getUserId());context.put("productId", request.getProductId());context.put("quantity", request.getQuantity());context.put("amount", request.getAmount());context.put("orderId", null); // 將在狀態流轉中設置return context;}/*** Saga狀態定義*/@SagaOrchestrationStartpublic void startOrderProcess(SagaTransactionContext context) {log.info("Saga開始 - 訂單處理: userId={}", context.getVariable("userId"));}@SagaOrchestrationTask("createOrder")public void createOrder(SagaTransactionContext context) {log.info("Saga步驟1 - 創建訂單");// 創建訂單邏輯Order order = orderService.createOrderLocal((Long) context.getVariable("userId"),(Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"),(BigDecimal) context.getVariable("amount"));context.setVariable("orderId", order.getId());log.info("訂單創建成功: orderId={}", order.getId());}@SagaOrchestrationTask("deductBalance")public void deductBalance(SagaTransactionContext context) {log.info("Saga步驟2 - 扣減余額");accountService.deductBalanceLocal((Long) context.getVariable("userId"),(BigDecimal) context.getVariable("amount"));log.info("余額扣減成功");}@SagaOrchestrationTask("reduceStock")public void reduceStock(SagaTransactionContext context) {log.info("Saga步驟3 - 扣減庫存");productService.reduceStockLocal((Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"));log.info("庫存扣減成功");}@SagaOrchestrationTask("updateOrderStatus")public void updateOrderStatus(SagaTransactionContext context) {log.info("Saga步驟4 - 更新訂單狀態");orderService.updateOrderStatusLocal((Long) context.getVariable("orderId"),OrderStatus.SUCCESS);log.info("訂單狀態更新成功");}// 補償方法@SagaOrchestrationCompensation("createOrder")public void compensateCreateOrder(SagaTransactionContext context) {log.info("Saga補償 - 取消訂單");Long orderId = (Long) context.getVariable("orderId");if (orderId != null) {orderService.cancelOrderLocal(orderId);log.info("訂單取消完成: orderId={}", orderId);}}@SagaOrchestrationCompensation("deductBalance")public void compensateDeductBalance(SagaTransactionContext context) {log.info("Saga補償 - 恢復余額");accountService.refundBalanceLocal((Long) context.getVariable("userId"),(BigDecimal) context.getVariable("amount"));log.info("余額恢復完成");}@SagaOrchestrationCompensation("reduceStock")public void compensateReduceStock(SagaTransactionContext context) {log.info("Saga補償 - 恢復庫存");productService.restoreStockLocal((Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"));log.info("庫存恢復完成");}
}

🎯 面試重點總結

💡 分布式事務架構師面試題

1. 事務模式選擇

Q: 什么場景選擇TCC?什么場景選擇Saga?
A:

  • TCC適用場景:資金交易、庫存扣減等需要強一致性的核心業務
  • Saga適用場景:訂單流程、批處理等長事務業務流程
  • 選擇依據:一致性要求、業務復雜度、性能要求
2. 分布式事務設計

Q: 如何設計一個高可用的分布式事務系統?
A:

  • 冪等性設計:防重試、防重復提交
  • 補償機制:業務補償、技術補償
  • 監控告警:事務狀態監控、異常告警
  • 容錯處理:超時重試、人工介入
3. 性能優化

Q: 分布式事務性能優化策略?
A:

  • 異步處理:非關鍵步驟異步執行
  • 批量操作:減少網絡開銷
  • 緩存優化:減少數據庫訪問
  • 分片策略:避免熱點數據

🎖? 分布式事務架構師核心能力

  1. 方案選型能力:根據業務特點選擇合適的事務模式
  2. 系統設計能力:設計高可用、高性能的事務系統
  3. 問題診斷能力:快速定位和解決分布式事務問題
  4. 優化調優能力:持續優化事務系統性能

🔄 分布式事務是分布式系統的核心挑戰!掌握技術選型與實現原理,構建高可靠的分布式事務系統!


📌 行動指南

  1. 點贊 → 讓更多Java開發者掌握分布式技術
  2. 評論 → 留言"分布式技術"領取[分布式系統設計模板]
  3. 關注 → 追蹤更新《更多Java技術精彩內容》(已寫完待發布)
  4. 贊賞 → 解鎖完整源碼+專屬技術咨詢

🚀 下期預告
《更多Java技術精彩內容》關注可搶先看

📚 相關推薦

  • 漫畫Java基礎
  • 漫畫Spring全家桶
  • 漫畫JVM調優

讓我們一起在Java的世界里探索更多精彩內容! 🚀

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

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

相關文章

液冷智算數據中心崛起,AI算力聯動PC Farm與云智算開拓新藍海(二)

從算法革新到基礎設施升級&#xff0c;從行業滲透到地域布局&#xff0c;人工智能算力正以 “規模擴張 效率提升”雙輪驅動中國數字經濟轉型。中國智能算力規模將在 2025 年突破 1000 EFLOPS&#xff0c;2028 年達到 2781.9 EFLOPS&#xff0c;五年復合增長率 46.2%&#xff0…

《QtPy:Python與Qt的完美橋梁》

QtPy 是什么 在 Python 的廣袤編程宇宙中&#xff0c;當涉及到圖形用戶界面&#xff08;GUI&#xff09;開發&#xff0c;Qt 框架宛如一顆璀璨的明星&#xff0c;散發著獨特的魅力。而 QtPy&#xff0c;作為 Python 與 Qt 生態系統交互中的關鍵角色&#xff0c;更是為開發者們開…

ubuntu環境下調試 RT-Thread

調試 RT-Thread 下載源碼 github 搜索 RT-Thread 下載源碼 安裝 python scons 環境 你已經安裝了 kconfiglib&#xff0c;但 scons --menuconfig 仍然提示找不到它。這種情況通常是由于 Python 環境不一致 導致的&#xff1a;你在一個 Python 環境中安裝了 kconfiglib&#xff…

【數據結構初階】--順序表(二)

&#x1f525;個人主頁&#xff1a;草莓熊Lotso &#x1f3ac;作者簡介&#xff1a;C研發方向學習者 &#x1f4d6;個人專欄&#xff1a; 《C語言》 《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》 ??人生格言&#xff1a;生活是默默的堅持&#xff0c;毅力是永久的…

Java中的方法傳參機制

1. 概述Java中的方法傳參機制分為兩種&#xff1a;值傳遞&#xff08;Pass by Value&#xff09; 和 引用傳遞&#xff08;Pass by Reference&#xff09;。然而&#xff0c;Java中所有的參數傳遞都是值傳遞&#xff0c;只不過對于對象來說&#xff0c;傳遞的是對象的引用地址的…

C++——this關鍵字和new關鍵字

一、this 關鍵字1. 什么是 this&#xff1f;this 是 C 中的一個隱式指針&#xff0c;它指向當前對象&#xff08;即調用成員函數的對象&#xff09;&#xff0c;在成員函數內部使用&#xff0c;用于引用調用該函數的對象。每個類的非靜態成員函數內部都可以使用 this。使用 thi…

Python中類靜態方法:@classmethod/@staticmethod詳解和實戰示例

在 Python 中&#xff0c;類方法 (classmethod) 和靜態方法 (staticmethod) 是類作用域下的兩種特殊方法。它們使用裝飾器定義&#xff0c;并且與實例方法 (def func(self)) 的行為有所不同。1. 三種方法的對比概覽方法類型是否訪問實例 (self)是否訪問類 (cls)典型用途實例方法…

FastGPT革命:下一代語言模型的極速進化

本文深度解析FastGPT核心技術架構&#xff0c;涵蓋分布式推理、量化壓縮、硬件加速等前沿方案&#xff0c;包含完整落地實踐指南&#xff0c;助你掌握大模型高效部署的終極武器。引言&#xff1a;當大模型遭遇速度瓶頸2023年&#xff0c;ChatGPT引爆全球AI熱潮&#xff0c;但企…

Geant4 安裝---Ubuntu

安裝工具 C/C工具包 sudo apt install build-essentialCmake sudo apt install -y cmakeccmake sudo apt install -y cmake-curses-gui安裝Qt可視化工具(不需要可視化可以不安裝) sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtcreator 安裝Ope…

Spring Boot中請求參數讀取方式

目錄 一、前言 二、六種參數讀取方式 1.RequestParam 2.PathVariable 3.RequestBody 4.RequestHeader 5.CookieValue 6.MatrixVariable 三、對比和搭配 1.適用方法類型及建議使用場景 2.建議使用的請求路徑注解 3. 多種參數同時使用 4.同一請求不同方案&#xff1f…

2025華為OD機試真題最新題庫 (B+C+D+E+2025A+2025B卷) + 在線OJ在線刷題使用(C++、Java、Python C語言 JS合集)(正在更新2025B卷,目前已收錄710道)

2025年&#xff0c;已經開始使用AB卷題庫&#xff0c;題目和往期一樣&#xff0c;舊題加新題的組合&#xff0c;有題目第一時間更新&#xff0c;大家可以跟著繼續學習&#xff0c;目前使用復用題較多&#xff0c;可在OJ上直接找到對應的AB卷學習&#xff0c;可以放心學習&#…

分析新舊因子相關性

計算一組新因子、并分析它們與已有因子間的相關性1. 導入庫和初始化環境功能代碼解析數據加載2. 定義新因子計算函數功能代碼解析因子 1&#xff1a;波動率過濾器&#xff08;filter_001_1&#xff09;因子 2&#xff1a;ATR 過濾器&#xff08;filter_001_2&#xff09;因子 3…

Unity Demo——3D平臺跳躍游戲筆記

今天是一個3D平臺跳躍游戲的筆記。我們按照以下分類來對這個項目的代碼進行學習&#xff1a;核心游戲系統 (Core Game Systems)核心游戲系統是IkunOdyssey項目的基礎&#xff0c;負責所有游戲對象&#xff08;如玩家、敵人、道具等&#xff09;的通用行為和物理交互。它通過實體…

【C語言】回調函數、轉移表、qsort 使用與基于qsort改造冒泡排序

文章目錄數組指針/指針數組函數指針函數指針數組函數指針數組用途(轉移表)回調函數qsort函數基于qsort改造冒泡排序源碼數組指針/指針數組 int arr1[5] { 1,2,3,4,5 };int (*p1)[5] &arr1; //p1是數組指針變量int* arr2[5] { 0 }; //arr2是指針數組指針數組是存放指…

vue3 uniapp 使用ref更新值后子組件沒有更新 ref reactive的區別?使用from from -item執行表單驗證一直提示沒有值

遇到這樣一個問題&#xff0c;我有個1個頁面A&#xff0c;一個from表單組件&#xff0c;一個form-item組件&#xff0c; 使用是這樣的&#xff0c;我在父組件A中使用 &#xff0c;執行表單驗證一直提示沒有值咱們先來講一講ref 和reactive的區別 ref 用來創建一個基本類型或單…

PyQt5布局管理(QBoxLayout(框布局))

QBoxLayout&#xff08;框布局&#xff09; 采用QBoxLayout類可以在水平和垂直方向上排列控件&#xff0c;QHBoxLayout和 QVBoxLayout類繼承自QBoxLayout類。 QHBoxLayout&#xff08;水平布局&#xff09; 采用QHBoxLayout類&#xff0c;按照從左到右的順序來添加控件。QHBoxL…

Grok 4作戰圖刷爆全網,80%華人橫掃硅谷!清華上交校友領銜,95后站C位

來源 | 新智元短短兩年&#xff0c;馬斯克Grok 4的橫空出世&#xff0c;讓xAI團隊一舉站上AI之巔。昨日一小時發布會&#xff0c;Grok 4讓所有人大開眼界&#xff0c;直接刷爆了AIME 2025、人類最后的考試&#xff08;HLE&#xff09;兩大基準。這是狂堆20萬GPU才換來的驚人成果…

AI大模型(七)Langchain核心模塊與實戰(二)

Langchain核心模塊與實戰&#xff08;二&#xff09;Langchian向量數據庫檢索Langchian構建向量數據庫和檢索器批量搜索返回與之相似度最高的第一個檢索器和模型結合得到非籠統的答案LangChain構建代理通過代理去調用Langchain構建RAG的對話應用包含歷史記錄的對話生成Langchia…

Flutter基礎(前端教程①-容器和控件位置)

一個紅色背景的 Container垂直排列的 Column 布局中央的 ElevatedButton按鈕下方的白色文本import package:flutter/material.dart;void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);overrideWidget bu…

CSS flex

目錄 flex-box和flex-item 主軸和副軸 ?編輯 flex-box的屬性 flex-direction flex-wrap flex-flow justify-content ?編輯?align-items align-content flex-item的屬性 flex-basis flex-grow flex-shrink flex flex-box和flex-item 當把一個塊級元素的displ…