目錄
概述
Springcloud 整合 Seata
數據庫腳本
服務依賴
Springboot 配置
代碼改造
AT模式下的數據隔離
寫隔離
讀隔離
概述
? ?Seata 的 AT 模式是 Seata 的默認模式,它的原理是依賴于數據庫事務,以數據庫事務保證本地事務分支特性,結合 Seata的 Undo 日志記錄做事務補償,來實現的一種二階段事務。總體來講,Seata 的AT模式使用起來比較簡單,對業務代碼的侵入性比較低。
?Demo
? ?這里附上seata的學習代碼demo,開箱即用。包含AT/TCC/XA等模式的使用案例https://download.csdn.net/download/lmj3732018/88864802
Springcloud 整合 Seata
數據庫腳本
?AT 模式需要在每個本地事務分支所在的數據庫中添加一個 undo_log 表,用于存儲本地事務分支的事務記錄。
數據庫腳本地址:https://github.com/apache/incubator-seata/blob/v1.7.0/script/client/at/db/mysql.sql
服務依賴
? Seata 的依賴版本最好參照官網推薦的版本對照,否則,可能出現不兼容的一些問題,同時 Seata 客戶端與服務端的版本也最好保持一致
?POM依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!--nacos 注冊中心-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency><!-- seata-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
Springboot 配置
seata:application-id: ${spring.application.name}# 這個值要與服務端 service.vgroupMapping.default_tx_group=default 相對應,服務端的值default與下面的 cluster: default 對應。tx-service-group: default_tx_groupregistry:type: nacosnacos:application: seata-serverserver-addr: 192.168.122.120:8848namespace: seata-idgroup: SEATA_GROUPusername: nacospassword: nacoscluster: defaultconfig:type: nacosnacos:server-addr: 192.168.122.120:8848namespace: seata-idgroup: SEATA_GROUPdata-id: seataServer.propertiesusername: nacospassword: nacos
代碼改造
代碼上的改造比較簡單,只需在事務發起者的接口方法上添加一個@GlobalTransactional(name="createOrder",rollbackFor=Exception.class)注解。分支事務那邊則不用做任何處理
@Override//@Transactional@GlobalTransactional(name="createOrder",rollbackFor=Exception.class)public Order saveOrder(OrderVo orderVo) {log.info("=============用戶下單=================");log.info("當前 XID: {}", RootContext.getXID());// 保存訂單Order order = new Order();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 ? "成功" : "失敗");//扣減庫存storageFeignService.deduct(orderVo.getCommodityCode(), orderVo.getCount());if(true){throw new RuntimeException();}//扣減余額Boolean debit= accountFeignService.debit(orderVo.getUserId(), orderVo.getMoney());// if(!debit){
// // 解決 feign整合sentinel降級導致Seata失效的處理
// throw new RuntimeException("賬戶服務異常降級了");
// }//更新訂單Integer updateOrderRecord = orderMapper.updateOrderStatus(order.getId(),OrderStatus.SUCCESS.getValue());log.info("更新訂單id:{} {}", order.getId(), updateOrderRecord > 0 ? "成功" : "失敗");return order;}
AT模式下的數據隔離
寫隔離
AT模式下通過全局鎖來保證寫操作的隔離性,避免產生臟讀。當全局事務A在操作某一條記錄時,會給這條記錄加一個全局鎖,所謂的全局鎖實際是指這條記錄的ID,當本地事務提交,而全局事務沒提交時。我們雖然通過直接操作數據庫可以看到這條提交的數據,但是當開啟另一個全局事務去操作這條數據時,則會先判斷全局鎖的存在,如果存在則默認將當前事務回滾(也可修改策略為不斷嘗試獲取全局鎖)。
讀隔離
AT模式默認情況下,如果數據庫的隔離級別為“讀已提交”,則全局事務的隔離級別為"讀未提交"。AT模式僅僅對 帶有 "select? for update"的語句會檢查全局鎖。