分享一個seata demo,講兩個個問題


  Seata,阿里開源的分布式事務框架,多的我就不介紹了,了解詳細介紹,請看官網。seata spring boot入門,可以看我上一篇博客《Spring boot微服務如何集成fescar解決分布式事務問題?》(fescar后來更名為seata)。

  本篇,將介紹,同時使用seata的tcc模式和at模式的一些問題。點擊demo,可查看相關源代碼。

第一個問題:數據源使用seata代理的數據源,同時使用TCC模式,將導致注冊到TC的分支事務多一倍

  

  在上一篇博客中,我們說到,要讓分支事務加入全局事務,需要分支事務rm獲得全局事務的xid,所以我們通過feign將xid傳遞到下游的微服務。但是AT模式的rm在下游服務的代理數據源處,TCC模式的rm在上游服務的TccAction處做的代理。此時要解決分支事務重復注冊的問題,在使用TCC模式的時候就不能把xid傳遞到下游服務,這樣,下游服務數據源代理處判斷到這個數據庫操作不在全局事務中,就不會向TC注冊。

  解決的辦法:我們在feign header里加入一個標識,標志此請求是不是TCC模式的請求,如果是,則不將xid傳遞到下游服務。

@Component
public class RequestHeaderInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        boolean seataTransactionATMode = true;
        if (attributes!=null) {
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {

                Map<String, Collection<String>> resolvedHeaders = new CaseInsensitiveKeyMap<>();
                resolvedHeaders.putAll(template.headers());

                while (headerNames.hasMoreElements()) {
                    String name = headerNames.nextElement();
                    if (!resolvedHeaders.containsKey(name)) {
                        String values = request.getHeader(name);
                        List<String> headers = new ArrayList<String>();
                        headers.addAll(Arrays.asList(values));
                        resolvedHeaders.put(name, headers);
                    }
                }
                template.headers(null);
                template.headers(resolvedHeaders);
            }
        }
        Map<String, Collection<String>> headers = template.headers();
        if(headers!=null){
            Collection<String> values = headers.getOrDefault(SeataConstants.TRANSACTION_MODE_HEADER,null);
            if (values==null) {
                values = headers.getOrDefault(SeataConstants.TRANSACTION_MODE_HEADER.toLowerCase(),null);
            }
            if(values!=null&&values.contains("TCC")){
                seataTransactionATMode = false;
            }
        }
        if(seataTransactionATMode) {
            String xid = RootContext.getXID();
            if (StringUtils.isNotBlank(xid)) {
                template.header(SeataConstants.XID_HEADER, xid);
            }
        }
    }
}

 

 

使用tcc模式有一個點需要注意,

    @TwoPhaseBusinessAction(name = "CreateOrderTccAction" , commitMethod = "commit", rollbackMethod = "rollback")
    public boolean prepare(BusinessActionContext actionContext, List<SoMaster> soMasters, @BusinessActionContextParameter(paramName = "SoSysNos") String soSysNos) throws BusinessException;

那就是BusinessActionContextParameter盡量使用簡單類型,如果是復雜類型,在注冊分支事務時會被序列化成json字符串,把上下文數據存到session。提交或者重試的時候,從actionContext獲取參數的時候actionContext.getActionContext("your argument")返回的是個object對象,此對象是個jsonObject,無法直接轉為復雜類型,需要tostring,再json反序列化。

第二個問題:在目前的undolog序列化協議中,數據庫里bigint類型的數據,被序列化后,再在undo回滾時反序列化回object類型,真實的值類型變成了int型

{"branchId":2013531184,"sqlUndoLogs":[{"afterImage":{"rows":[{"fields":[{"keyType":"PrimaryKey","name":"sysno","type":-5,"value":1},{"keyType":"NULL","name":"available_qty","type":4,"value":999992},{"keyType":"NULL","name":"allocated_qty","type":4,"value":8}]}],"tableName":"inventory"},"beforeImage":{"rows":[{"fields":[{"keyType":"PrimaryKey","name":"sysno","type":-5,"value":1},{"keyType":"NULL","name":"available_qty","type":4,"value":999994},{"keyType":"NULL","name":"allocated_qty","type":4,"value":6}]}],"tableName":"inventory"},"sqlType":"UPDATE","tableName":"inventory"}],"xid":"172.16.4.137:8091:2013531176"}

如上,{"keyType":"PrimaryKey","name":"sysno","type":-5,"value":1},sysno,type -5表示這是一個bigint的類型,反序列化后,value的真正值類型是int型,這個問題可以參考issue 1139

在目前的版本0.6.1,已經支持TC的高可用嗎,但這個bug還沒有解決,如果使用類型判斷去做轉換來修復這個bug,預計會寫很多if else。官方回復的解決辦法是,他們會修改序列化的協議來解決這個bug。期待官方盡快修復這個bug。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM