成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

借助Nacos高效配置與實踐Seata事務的TCC模式

開發 前端
對于已經空回滾的業務,之前被阻塞的try操作恢復,繼續執行try,就永遠不可能confirm或cancel ,事務一直處于中間狀態,這就是業務懸掛。

實現

TCC 模式

TCC模式與AT模式非常相似,每階段都是獨立事務,不同的是TCC通過人工編碼來實現數據恢復。需要實現三個方法:

  • Try:資源的檢測和預留;
  • Confirm:完成資源操作業務;要求 Try 成功 Confirm 一定要能成功。
  • Cancel:預留資源釋放,可以理解為try的反向操作。

流程分析

圖片圖片

階段一(Try):檢查余額是否充足,如果充足則凍結金額增加30元,可用余額扣除30

圖片圖片

圖片圖片

此時,總金額 = 凍結金額 + 可用金額,數量依然是100不變,事務直接提交無需等待其它事務。

階段二(Confirm) :假如要提交,則凍結金額扣減30

圖片圖片

確認可以提交,不過之前可用金額已經扣減過了,這里只要清除凍結金額就好了,此時,總金額 = 凍結金額 + 可用金額 = 0 + 70 = 70

階段二(Cancel):如果要回滾,則凍結金額扣減30,可用余額增加30

圖片圖片

需要回滾,那么就要釋放凍結金額,恢復可用金額

Seata的TCC模型

圖片圖片

代碼樣例

配置和依賴參考之前《利用Nacos實現Seata事務模式(XA與AT)的快速配置與靈活切換》即可

bank3:

聲明TCC接口

@LocalTCC
public interface AccountInTcc {

    @TwoPhaseBusinessAction(name = "prepareDeductMoney", commitMethod = "commitDeductMoney", rollbackMethod = "rollbackDeductMoney")
    boolean prepareDeductMoney(BusinessActionContext businessActionContext,
                               @BusinessActionContextParameter(paramName = "accountNo")String accountNo,
                               @BusinessActionContextParameter(paramName = "amount")Double amount);

    /**
     * 提交扣款
     * 二階段confirm確認方法、可以另命名,但要保證與commitMethod一致
     */
    boolean commitDeductMoney(BusinessActionContext businessActionContext);
    /**
     * 回滾扣款
     * 二階段回滾方法,要保證與rollbackMethod一致
     */
    boolean rollbackDeductMoney(BusinessActionContext businessActionContext);
}

具體實現:

@Component
public class AccountInTccImpl implements AccountInTcc {

    @Autowired
    private AccountInfoMapper accountInfoMapper;

    @Transactional
    @Override
    public boolean prepareDeductMoney(BusinessActionContext businessActionContext, String accountNo, Double amount) {
        String xid = businessActionContext.getXid();
        // 冪等性判斷
        if (TccActionResultWrap.hasPrepareResult(xid)) {
            return true;
        }

        // 避免空懸掛,已經執行過回滾了就不能再預留資源
        if (TccActionResultWrap.hasRollbackResult(xid) || TccActionResultWrap.hasCommitResult(xid)) {
            return false;
        }
        // 預留資源
        boolean result = accountInfoMapper.prepareDeductMoney(accountNo,amount) > 0;

        // 記錄執行結果,以便回滾時判斷是否是空回滾
        TccActionResultWrap.prepareSuccess(xid);
        System.out.println("============prepare==============");
        return result;
    }

    // 保證提交邏輯的原子性
    @Transactional
    @Override
    public boolean commitDeductMoney(BusinessActionContext businessActionContext) {
        String xid = businessActionContext.getXid();
        // 冪等性判斷
        if (TccActionResultWrap.hasCommitResult(xid)) {
            return true;
        }
        Map<String, Object> actionContext = businessActionContext.getActionContext();
        String accountNo = (String) actionContext.get("accountNo");
        BigDecimal amount = (BigDecimal) actionContext.get("amount");
        // 執行提交操作,扣除預留款
        boolean result = accountInfoMapper.commitDeductMoney(accountNo,amount.doubleValue()) > 0;
        // 清除預留結果
        TccActionResultWrap.removePrepareResult(xid);
        // 設置提交結果
        TccActionResultWrap.commitSuccess(xid);
        System.out.println("============commit==============");
        return result;
    }

    @Transactional
    @Override
    public boolean rollbackDeductMoney(BusinessActionContext businessActionContext) {
        String xid = businessActionContext.getXid();
        // 冪等性判斷
        if (TccActionResultWrap.hasRollbackResult(xid)) {
            return true;
        }
        // 沒有預留資源結果,回滾不做任何處理;
        if (!TccActionResultWrap.hasPrepareResult(xid)) {
            // 設置回滾結果,防止空回滾
            TccActionResultWrap.rollbackSuccess(xid);
            return true;
        }
        // 執行回滾
        Map<String, Object> actionContext = businessActionContext.getActionContext();
        String accountNo = (String) actionContext.get("accountNo");
        BigDecimal amount = (BigDecimal) actionContext.get("amount");
        boolean result = accountInfoMapper.rollbackDeductMoney(accountNo,amount.doubleValue()) > 0;
        // 清除預留結果
        TccActionResultWrap.removePrepareResult(xid);
        // 設置回滾結果
        TccActionResultWrap.rollbackSuccess(xid);
        System.out.println("============rollback==============");
        return result;
    }
}

業務層:

@Autowired
  private AccountInTcc accountInTcc;

  @Override
  public Boolean deductMoney(String accountNo, Double amount) {
      return accountInTcc.prepareDeductMoney(null,accountNo,amount);
  }

參數中的BusinessActionContext不需要開發人員自己傳遞,直接給null即可,Seata會自動處理。

mapper:

@Update("update account_info set account_balance = account_balance - #{amount}, frozen_money = frozen_money + #{amount} where account_no = #{accountNo} and account_balance >= #{amount}")
    int prepareDeductMoney(@Param("accountNo") String accountNo, @Param("amount") Double amount);
    @Update("update account_info set frozen_money = frozen_money - #{amount} where account_no = #{accountNo}")
    int commitDeductMoney(@Param("accountNo") String accountNo, @Param("amount") Double amount);
    @Update("update account_info set account_balance = account_balance + #{amount}, frozen_money = frozen_money - #{amount} where account_no = #{accountNo}")
    int rollbackDeductMoney(@Param("accountNo") String accountNo, @Param("amount") Double amount);

bank4服務調用:

@GlobalTransactional
    @Override
    public Boolean addMoney(String accountNo, Double amount) {

        String result = bank3Client.deduct(amount);
        if("true".equalsIgnoreCase(result)){
            Boolean flag = baseMapper.addMoney(accountNo,amount) > 0;
            if(amount != 30 ) throw new RuntimeException("bank4 make exception amount != 30");
            return flag;
        }
        return false;
    }

TCC的優點:

  • 一階段完成直接提交事務,釋放數據庫資源,性能好
  • 相比AT模型,無需生成快照,無需使用全局鎖,性能最強
  • 不依賴數據庫事務,而是依賴補償操作,可以用于非事務型數據庫

TCC的缺點:

  • 有代碼侵入,需要人為編寫try、Confirm和Cancel接口,太麻煩
  • 軟狀態,事務是最終一致
  • 需要考慮Confirm和Cancel的失敗情況,做好冪等處理
  • 空回滾:當某分支事務的try階段阻塞時,可能導致全局事務超時而觸發二階段的cancel操作。在未執行try操作時先執行了cancel操作,這時cancel不能做回滾,就是空回滾
  • 業務懸掛:對于已經空回滾的業務,之前被阻塞的try操作恢復,繼續執行try,就永遠不可能confirm或cancel ,事務一直處于中間狀態,這就是業務懸掛。

圖片圖片

執行cancel操作時,應當判斷try是否已經執行,如果尚未執行,則應該空回滾。

執行try操作時,應當判斷cancel是否已經執行過了,如果已經執行,應當阻止空回滾后的try操作,避免懸掛。

責任編輯:武曉燕 來源: 一安未來
相關推薦

2024-01-30 08:10:37

Nacos事務模式

2025-05-07 00:10:00

分布式事務TCC模式

2022-01-12 10:02:02

TCC模式 Seata

2025-04-30 10:44:02

2024-10-09 14:14:07

2023-05-17 00:15:11

TCCXA模式

2021-12-27 09:20:13

事務模式隔離

2025-02-08 10:56:18

2023-07-26 08:25:02

2025-04-28 00:44:04

2021-11-14 16:07:35

中間件阿里Seata

2022-06-21 08:27:22

Seata分布式事務

2022-07-03 14:03:57

分布式Seata

2020-04-28 12:18:08

Seata模式分布式

2024-12-09 09:35:00

2021-04-23 08:15:51

Seata XA AT

2023-10-24 08:25:20

TCC模式事務

2025-05-16 07:46:11

分布式事務服務

2019-05-16 09:00:06

云原生監控日志管理

2022-06-20 11:05:49

TCC模式commit
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美日本在线 | 99在线国产| 国产91久久久久蜜臀青青天草二 | 国产精品中文在线 | 国产午夜精品一区二区三区嫩草 | 黑人巨大精品 | 精品国产一区二区三区观看不卡 | 国产一区二区在线免费视频 | 天天天久久久 | 国产视频第一页 | 国产成人精品久久二区二区91 | 可以免费看的毛片 | 欧美日韩亚洲在线 | 国产真实精品久久二三区 | 国户精品久久久久久久久久久不卡 | 久久一久久 | 亚洲一区二区三区久久久 | 一区二区三区四区在线播放 | 国产一区二区三区四区 | 欧美激情在线播放 | 亚洲一区欧美一区 | 毛片免费观看视频 | 久久无毛 | 在线看一区二区 | 盗摄精品av一区二区三区 | 久久国内精品 | 久久一日本道色综合久久 | 自拍偷拍3p| 欧美美女爱爱视频 | 古装三级在线播放 | 成人在线播放网站 | 国产精品久久久久久久免费大片 | 北条麻妃一区二区三区在线观看 | 国产精品91视频 | 日韩欧美网 | 亚洲精品电影在线观看 | 国产 欧美 日韩 一区 | 色精品| 91精品久久久久久久久久入口 | 免费在线观看一区二区三区 | 国产欧美日韩综合精品一区二区 |