Hyperf方案 分布式事务(TCC 模式)

张开发
2026/4/17 20:49:20 15 分钟阅读

分享文章

Hyperf方案 分布式事务(TCC 模式)
直接用上面提到的 dtm-php/dtm-client它同时支持 Saga 和 TCC。 --- TCC vs Saga ┌────────┬──────────────────────┬─────────────┐ │ │ TCC │ Saga │ ├────────┼──────────────────────┼─────────────┤ │ 阶段 │ Try → Confirm/Cancel │ 正向 → 补偿 │ ├────────┼──────────────────────┼─────────────┤ │ 一致性 │ 强一致资源预留 │ 最终一致 │ ├────────┼──────────────────────┼─────────────┤ │ 适合 │ 库存/余额扣减 │ 长流程编排 │ └────────┴──────────────────────┴─────────────┘ --- 安装composerrequire dtm-php/dtm-client ---1. TCC 发起方?php namespace App\Service;use DtmClient\TCC;use DtmClient\TransContext;class OrderService{publicfunction__construct(private TCC$tcc){}publicfunctioncreateOrder(int$userId, int$productId, int$qty, float$amount): string{$baseUrlhttp://order-service/api/tcc;return$this-tcc-globalTransaction(function()use($baseUrl,$userId,$productId,$qty,$amount){// 预留库存$this-tcc-callBranch(body:[product_id$productId,qty$qty], tryUrl:{$baseUrl}/inventory/try, confirmUrl:{$baseUrl}/inventory/confirm, cancelUrl:{$baseUrl}/inventory/cancel,);// 预扣余额$this-tcc-callBranch(body:[user_id$userId,amount$amount], tryUrl:{$baseUrl}/account/try, confirmUrl:{$baseUrl}/account/confirm, cancelUrl:{$baseUrl}/account/cancel,);});}}---2. 库存子事务含幂等屏障?php namespace App\Controller;use DtmClient\Barrier;use Hyperf\HttpServer\Annotation\Controller;use Hyperf\HttpServer\Annotation\PostMapping;#[Controller(prefix: /api/tcc/inventory)]class InventoryTccController{publicfunction__construct(private Barrier$barrier){}// Try冻结库存#[PostMapping(path: try)]publicfunctiontry(): array{$productId$this-request-input(product_id);$qty$this-request-input(qty);$this-barrier-call(function()use($productId,$qty){$stockInventory::lockForUpdate()-findOrFail($productId);if($stock-available$qty){throw new\RuntimeException(Insufficient stock);}$stock-decrement(available,$qty);$stock-increment(frozen,$qty);});return[resultSUCCESS];}// Confirm扣减冻结库存#[PostMapping(path: confirm)]publicfunctionconfirm(): array{$productId$this-request-input(product_id);$qty$this-request-input(qty);$this-barrier-call(function()use($productId,$qty){Inventory::findOrFail($productId)-decrement(frozen,$qty);});return[resultSUCCESS];}// Cancel解冻库存#[PostMapping(path: cancel)]publicfunctioncancel(): array{$productId$this-request-input(product_id);$qty$this-request-input(qty);$this-barrier-call(function()use($productId,$qty){$stockInventory::findOrFail($productId);$stock-decrement(frozen,$qty);$stock-increment(available,$qty);});return[resultSUCCESS];}}---3. 账户子事务#[Controller(prefix: /api/tcc/account)]class AccountTccController{publicfunction__construct(private Barrier$barrier){}// Try冻结金额#[PostMapping(path: try)]publicfunctiontry(): array{$this-barrier-call(function(){$userId$this-request-input(user_id);$amount$this-request-input(amount);$accountAccount::lockForUpdate()-findOrFail($userId);if($account-balance$amount){throw new\RuntimeException(Insufficient balance);}$account-decrement(balance,$amount);$account-increment(frozen,$amount);});return[resultSUCCESS];}// Confirm扣减冻结金额#[PostMapping(path: confirm)]publicfunctionconfirm(): array{$this-barrier-call(function(){Account::findOrFail($this-request-input(user_id))-decrement(frozen,$this-request-input(amount));});return[resultSUCCESS];}// Cancel解冻金额#[PostMapping(path: cancel)]publicfunctioncancel(): array{$this-barrier-call(function(){$accountAccount::findOrFail($this-request-input(user_id));$account-decrement(frozen,$this-request-input(amount));$account-increment(balance,$this-request-input(amount));});return[resultSUCCESS];}}---4. Migration冻结字段 Schema::table(inventories,function(Blueprint$table){$table-unsignedInteger(available)-default(0);$table-unsignedInteger(frozen)-default(0);// TCC 预留});Schema::table(accounts,function(Blueprint$table){$table-decimal(balance,12,2)-default(0);$table-decimal(frozen,12,2)-default(0);// TCC 预留});--- 核心要点 - Barrier::call()自动处理幂等/悬挂/空回滚三个接口都必须包裹 - Try 失败抛异常 → DTM 自动触发所有分支的 Cancel - frozen 字段是 TCC 的关键资源预留而非直接扣减 - Confirm/Cancel 必须幂等DTM 可能重试

更多文章