分享一个seata demo,讲两个个问题

释放双眼,带上耳机,听听看~!

  Seata,阿里开源的分布式事务框架,多的我就不介绍了,了解详细介绍,请看官网。seata spring boot入门,可以看我上一篇博客《Spring boot微服务如何集成fescar解决分布式事务问题?》(fescar后来更名为seata)。

  本篇,将介绍,同时使用seata的tcc模式和at模式的一些问题。点击demo,可查看相关源代码。

第一个问题:数据源使用seata代理的数据源,同时使用TCC模式,将导致注册到TC的分支事务多一倍

分享一个seata demo,讲两个个问题

  

  在上一篇博客中,我们说到,要让分支事务加入全局事务,需要分支事务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);
            }
        }
    }
}

 

分享一个seata demo,讲两个个问题

第二个问题:在目前的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。

给TA打赏
共{{data.count}}人
人已打赏
随笔日记

如果当前没有拿得出手的简历,也别慌,努力的话最多两年情况就能改变

2020-11-9 5:18:57

随笔日记

智飞生物代理产品营收占比超74% 红利难持续

2020-11-9 5:18:59

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索