目錄
概述
使用
依賴與配置
代碼
概述
? ?TCC 模式是一種侵入式的分布式事務解決方案,它不依賴于數據庫的事務,而是要求開發者自定義完成 預提交、提交、回滾的方法邏輯。因此,它是一個種偏?復雜、靈活、有侵入性?的分布式事務處理方案。
?Demo
? ?這里附上seata的學習代碼demo,開箱即用。包含AT/TCC/XA等模式的使用案例https://download.csdn.net/download/lmj3732018/88864802
使用
依賴與配置
? ? Seata的TCC模式依賴和配置與AT模式完全一致,只是TCC模式不需要定義 undo_log 數據庫表,這里不再贅述。
代碼
? ? 1. 在使用時,我們需要在多個本地事務分支的外層使用 @GlobalTransactional 開啟全局事務
@Override
@GlobalTransactional(name="createOrder",rollbackFor=Exception.class)
public Order saveOrder(OrderVo orderVo) {log.info("=============用戶下單=================");log.info("當前 XID: {}", RootContext.getXID());//獲取全局唯一訂單號 測試使用Long orderId = UUIDGenerator.generateUUID();//階段一: 創建訂單Order order = orderService.prepareSaveOrder(orderVo,orderId);//扣減庫存storageFeignService.deduct(orderVo.getCommodityCode(), orderVo.getCount());//扣減余額accountFeignService.debit(orderVo.getUserId(), orderVo.getMoney());return order;
}
2. 定義各個本地事務分支的預提交、提交、回滾方法
OrderService 接口
/**** 通過 @LocalTCC 這個注解,RM 初始化的時候會向 TC 注冊一個分支事務。*/
@LocalTCC
public interface OrderService {/*** TCC的try方法:保存訂單信息,狀態為支付中** 定義兩階段提交,在try階段通過@TwoPhaseBusinessAction注解定義了分支事務的 resourceId,commit和 cancel 方法* name = 該tcc的bean名稱,全局唯一* commitMethod = commit 為二階段確認方法* rollbackMethod = rollback 為二階段取消方法* BusinessActionContextParameter注解 傳遞參數到二階段中* useTCCFence seata1.5.1的新特性,用于解決TCC冪等,懸掛,空回滾問題,需增加日志表tcc_fence_log*/@TwoPhaseBusinessAction(name = "prepareSaveOrder", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)Order prepareSaveOrder(OrderVo orderVo, @BusinessActionContextParameter(paramName = "orderId") Long orderId);/**** TCC的confirm方法:訂單狀態改為支付成功** 二階段確認方法可以另命名,但要保證與commitMethod一致* context可以傳遞try方法的參數** @param actionContext* @return*/boolean commit(BusinessActionContext actionContext);/*** TCC的cancel方法:訂單狀態改為支付失敗* 二階段取消方法可以另命名,但要保證與rollbackMethod一致** @param actionContext* @return*/boolean rollback(BusinessActionContext actionContext);
}
OrderServiceImpl實現類
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Override@Transactional(rollbackFor = Exception.class)public Order prepareSaveOrder(OrderVo orderVo,@BusinessActionContextParameter(paramName = "orderId") Long orderId) {// 保存訂單Order order = new Order();order.setId(orderId);order.setUserId(orderVo.getUserId());order.setCommodityCode(orderVo.getCommodityCode());order.setCount(orderVo.getCount());order.setMoney(orderVo.getMoney());order.setStatus(OrderStatus.INIT.getValue());Integer saveOrderRecord = orderMapper.insert(order);log.info("保存訂單{}", saveOrderRecord > 0 ? "成功" : "失敗");return order;}@Overridepublic boolean commit(BusinessActionContext actionContext) {// 獲取訂單idlong orderId = Long.parseLong(actionContext.getActionContext("orderId").toString());//更新訂單狀態為支付成功Integer updateOrderRecord = orderMapper.updateOrderStatus(orderId, OrderStatus.SUCCESS.getValue());log.info("更新訂單id:{} {}", orderId, updateOrderRecord > 0 ? "成功" : "失敗");return true;}@Overridepublic boolean rollback(BusinessActionContext actionContext) {//獲取訂單idlong orderId = Long.parseLong(actionContext.getActionContext("orderId").toString());//更新訂單狀態為支付失敗Integer updateOrderRecord = orderMapper.updateOrderStatus(orderId, OrderStatus.FAIL.getValue());log.info("更新訂單id:{} {}", orderId, updateOrderRecord > 0 ? "成功" : "失敗");return true;}}
在 storageFeignService 及 accountFeignService的遠程方法中也是以同樣的方式定義上述三個方法。