問題復現
設備健康 business 服務調用 admin 服務,前者制造異常並成功回滾,后者未出現異常但是並未回滾
源碼分析
加上全局事務注解之后會走 io.seata.tm.api.TransactionalTemplate#execute 方法做事務相關處理;
該方法主要分為5個步驟:
第一步:獲取當前全局事務
第二步:開啟全局事務,並處理業務
第三步:業務異常則回滾事務
第四步:業務正常則提交事務
第五步:清理
問題定位
這次問題出現在第一步,從上下文獲取當前全局事務
business 服務是全局事務的第一段,拿不到 xid 理所應當,會創建一個全局事務對象
admin 服務是全局事務的第二段,理論上 business 會把 xid 傳遞給 admin;
事實上發現 RootContext 並未獲取到 xid,從而 admin 也創建一個全局事務對象;
這樣一來,business 和 admin 各自創建了自己的全局事務,xid 不同,導致 business 能夠正常回滾,admin 卻提交了自己的事務。
個人猜測是 request 把 xid 丟失了,沒有傳遞給下游;
果不其然 com.alibaba.cloud.seata.web.SeataHandlerInterceptor 打斷點,卻始終未進斷點
這里能斷定 com.alibaba.cloud.seata.web.SeataHandlerInterceptorConfiguration 未生效;
由於使用了 @ConditionalOnWebApplication,必須是 web mvc 項目才生效。
web mvc 自動配置 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration 前提是沒有
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport 這個 bean
所以罪魁禍首是 WebMvcConfigurationSupport
總結
項目總如果使用了 WebMvcConfigurationSupport 會直接導致 WebMvcConfigurer 不生效,那么需要將 SeataHandlerInterceptor 手動放到攔截器鏈路中;
個人建議實現 WebMvcConfigurer 而不是繼承 WebMvcConfigurationSupport,這樣的話一切都不會有問題。
seata 常見問題:http://seata.io/zh-cn/docs/overview/faq.html