分享一個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);
            }
        }
    }
}

 

第二個問題:在目前的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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章