精华内容
下载资源
问答
  • Spring Cloud Feign 及 Hystrix 回滚

    千次阅读 2018-08-09 13:49:38
    * 回滚事件,需要实现要回滚的对象接口,该回滚是被调用方要执行的业务逻辑. */ @Slf4j @Component class ProductClientFallback implements ProductClient { @Override public String productList(String msg...

    引入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
    </dependencies>

    启动类:

    @EnableFeignClients(basePackages = "club.cearnach")
    @SpringCloudApplication
    @ComponentScan(basePackages = "club.cearnach")
    public class OrderServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderServerApplication.class, args);
        }
    }

    声明一个Client , fallback指定要回滚的实现类.

    @FeignClient(name = "PRODUCT-SERVER", fallback = ProductClient.ProductClientFallback.class)
    public interface ProductClient {
        @GetMapping("/product/list")
        String productList(@RequestParam("msg") String msg);
    
        /**
         * 回滚事件,需要实现要回滚的对象接口,该回滚是被调用方要执行的业务逻辑.
         */
        @Slf4j
        @Component
        class ProductClientFallback implements ProductClient {
    
            @Override
            public String productList(String msg) {
                String info = "productList fallback()";
                log.info(info);
                return info;
            }
        }
    }

    在另外一个模块中引用该Client所在的模块.

    然后直接注入即可使用.

    @Autowired
        private ProductClient productClient;
     /**
         * HystrixCommand(fallbackMethod = "fallback") 指定单FeignClient不可用或者执行时抛出异常,需要回滚的方法
         *
         * @return
         */
        @GetMapping("/feign/list")
        @HystrixCommand(fallbackMethod = "fallback")
        public String feignList() {
            return productClient.productList("Fetch feign msg...");
        }
    
      /**
      * 该回滚是当前调用方执行失败时的回滚.
      */
    
        public String fallback() {
            return "invoke fallback()";
        }

    或者实现 FallbackProvider 接口,实习该接口后, fallbackMethod 就不会生效了.

    package com.xmut.osm.zuul.filter;
    
    import com.alibaba.fastjson.JSON;
    import com.xmut.osm.common.bean.ResultVO;
    import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.client.AbstractClientHttpResponse;
    import org.springframework.http.client.ClientHttpResponse;
    import org.springframework.stereotype.Component;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * @author 阮胜
     * @date 2018/7/22 20:01
     */
    @Component
    public class DefaultFallbackProviderImpl implements FallbackProvider {
        @Override
        public String getRoute() {
            return null;
        }
    
        @Override
        public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
            return new AbstractClientHttpResponse() {
                @Override
                public int getRawStatusCode() throws IOException {
                    return HttpStatus.OK.value();
                }
    
                @Override
                public String getStatusText() throws IOException {
                    return HttpStatus.OK.name();
                }
    
                @Override
                public void close() {
    
                }
    
                @Override
                public InputStream getBody() throws IOException {
                    ResultVO<String> resultVO = new ResultVO<>();
                    resultVO.setMessage("服务器正忙!");
                    resultVO.setSuccess(false);
                    return new ByteArrayInputStream(JSON.toJSONString(resultVO).getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
                    return httpHeaders;
                }
            };
        }
    }

    最后,需要在调用FeignClient的那一方配置文件中添加如下配置:

    feign:
      hystrix:
        enabled: true
    展开全文
  • 1,参考了网上一位大神的例子,说用Spring AOP来进行手动开启全局事务ID和事务回滚,貌似没啥欧用,可能我用法不对,代码如下 /** * @author jxys * @since 2020年6月8日09:37:55 * 类描述: 用于处理程序调用...

    解决方案
    1,参考了网上一位大神的例子,说用Spring AOP来进行手动开启全局事务ID和事务回滚,貌似没啥欧用,可能我用法不对,代码如下

    /**
     * @author jxys
     * @since 2020年6月8日09:37:55
     * 类描述: 用于处理程序调用发生异常的时候由于异常被处理以后无法触发事务,而进行的处理,使之可以正常的触发事务。
     */
    @Aspect
    @Component
    public class WorkAspect {
    
        private final static Logger logger = LoggerFactory.getLogger(WorkAspect.class);
        //io.seata.saga.engine.invoker
        @Before("execution(* com.jxysgzs.service.local.*.*(..))")
        public void before(JoinPoint joinPoint) throws TransactionException {
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            Method method = signature.getMethod();
            GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
            tx.begin(300000, "test-client");
            logger.info("**********创建分布式事务完毕" + tx.getXid());
        }
        
        @AfterThrowing(throwing = "e", pointcut = "execution(* com.jxysgzs.service.local.*.*(..))")
        public void doRecoveryActions(Throwable e) throws TransactionException {
            logger.info("方法执行异常:{}", e.getMessage());
            if (!StringUtils.isBlank(RootContext.getXID())) {
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
            }
        }
    
    }
    

    2.直接在降级方法里面手动回滚

    try {
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
            } catch (TransactionException e) {
                e.printStackTrace();
            }
    
    展开全文
  • seata1.0实现feign降级和全局异常处理的时候事务的回滚源码下载前言配置feign的降级实现feign降级的时候事务的回滚实现全局异常处理以后事务的回滚 源码下载 大家可以直接微信扫描上面的二维码关注我的公众号,然后...

    源码下载

    在这里插入图片描述
    大家可以直接微信扫描上面的二维码关注我的公众号,然后回复seata exception 里面就会给到源代码的下载地址同时会附上相应的视频教程,并定期的与大家分享相关的技术文章。

    前言

    在我们开发的过程中,如果出现异常,正常我们都会进行try…catch或者配置全局异常的补获处理,或者我们的分feign的服务降级,如果这时候我们使用分布式事务seata那么我们会发现我们的事务不会回滚了,难道使用我们的分布式事务我们就不能做异常的处理了吗?很明显这是不可能的,通过官方大神给的方案通过AOP动态创建/关闭Seata分布式事务我们找到了解决方案,我们这边文章的工程是基于基于seata1.0和spring cloud的Greenwich.SR2版本的分布式事务demo例子的实现全过程这篇文章的基础上进行改造的。

    配置feign的降级

    由于我们只需要验证一个服务降级即可,那么我们这次就直接验证我们的订单模块的account的服务降级,若是对feign的服务降级有不懂的可以直接看这篇博客[spring cloud的Hoxton.SR1版本的feign的优雅降级的实现],(https://linzhefeng23.blog.csdn.net/article/details/103710038)我们直接在order-server的feign底下创建一个impl包,同时创建一个AccountApiImpl实现AccountApi,代码如下:

    /**
     * @author linzf
     * @since 2019/12/27
     * 类描述:
     */
    @Component
    public class AccountApiImpl implements AccountApi {
    
    
        @Override
        public String decrease(Long userId, BigDecimal money) {
            System.out.println("我被服务降级了,回滚了吗?");
            return "我被服务降级了!";
        }
    }
    
    

    接着我们修改我们的AccountApi添加我们的fallback 修改以后代码如下:

    @FeignClient(value = "account-server",fallback = AccountApiImpl.class)
    public interface AccountApi {
    
        /**
         * 扣减账户余额
         * @param userId 用户id
         * @param money 金额
         * @return
         */
        @RequestMapping("/account/decrease")
        String decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
    }
    

    最后我们修改我们的account-server模块的AccountServiceImpl的decrease方法直接在该方法的后面抛出异常,模拟方法调用出错的实现,修改以后代码如下:

    @Service("accountServiceImpl")
    public class AccountServiceImpl implements AccountService{
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);
        @Autowired
        private AccountDao accountDao;
        @Autowired
        private OrderApi orderApi;
    
        /**
         * 扣减账户余额
         * @param userId 用户id
         * @param money 金额
         */
        @Override
        public void decrease(Long userId, BigDecimal money) {
            LOGGER.info("------->扣减账户开始account中");
            //模拟超时异常,全局事务回滚
    //        try {
    //            Thread.sleep(30*1000);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
            accountDao.decrease(userId,money);
            LOGGER.info("------->扣减账户结束account中");
    
            //修改订单状态,此调用会导致调用成环
            LOGGER.info("修改订单状态开始");
            String mes = orderApi.update(userId, money.multiply(new BigDecimal("0.09")),0);
            LOGGER.info("修改订单状态结束:{}",mes);
            throw new RuntimeException("我出错了,会被回滚吗?");
        }
    }
    

    最后还需要修改order-server的application.yml的配置文件的feign.hystrix.enabled属性的值设置为true,最后启动我们的seata-server、注册中心、account-server、order-server、storage-server,启动完成以后我们直接访问以下的地址:http://localhost:8180/order/create?userId=1&productId=1&count=10&money=100,这时候我们发现我们的order-server触发了事务的降级处理如下所示:
    在这里插入图片描述
    然后我们发现我们的事务并没有回滚,而是正常执行了,那这很明显不是我们想要的结果,那这时候怎么办呢,我们直接参考我们的官方大神给的方案通过AOP动态创建/关闭Seata分布式事务来解决我们的事务不回滚的问题。

    实现feign降级的时候事务的回滚

    直接在我们的account-server、order-server、storage-server工程底下创建一个config目录,然后创建我们的事务处理切面类【WorkAspect】代码如下:

    /**
     * @author linzf
     * @since 2019/12/27
     * 类描述: 用于处理程序调用发生异常的时候由于异常被处理以后无法触发事务,而进行的处理,使之可以正常的触发事务。
     */
    @Aspect
    @Component
    public class WorkAspect {
    
        private final static Logger logger = LoggerFactory.getLogger(WorkAspect.class);
    
        @Before("execution(* io.seata.sample.service.*.*(..))")
        public void before(JoinPoint joinPoint) throws TransactionException {
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            Method method = signature.getMethod();
            logger.info("拦截到需要分布式事务的方法," + method.getName());
            // 此处可用redis或者定时任务来获取一个key判断是否需要关闭分布式事务
            GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
            tx.begin(300000, "test-client");
            logger.info("创建分布式事务完毕" + tx.getXid());
        }
    
        @AfterThrowing(throwing = "e", pointcut = "execution(* io.seata.sample.service.*.*(..))")
        public void doRecoveryActions(Throwable e) throws TransactionException {
            logger.info("方法执行异常:{}", e.getMessage());
            if (!StringUtils.isBlank(RootContext.getXID())) {
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
            }
        }
    
    }
    
    

    这时候我们account-server的service方法中将【模拟超时异常,全局事务回滚】这段的注释给放开,然后直接访问:http://localhost:8180/order/create?userId=1&productId=1&count=10&money=100,然后我们发现我们的事务实现了回滚了,这就达到了我们想要的效果。

    实现全局异常处理以后事务的回滚

    我们直接在我们的account-server底下配置一个【GlobalExceptionsHandler】,代码如下:

    /**
     * @author linzf
     * @since 2019/5/29
     * 类描述:全局异常捕获处理
     */
    @ControllerAdvice
    public class GlobalExceptionsHandler {
    
        private Logger log = LoggerFactory.getLogger(GlobalExceptionsHandler.class);
    
        /**
         * 功能描述:全局异常处理
         *
         * @param e
         * @return 返回处理结果
         * @throws Exception
         */
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public Object errorHandler(Exception e) throws Exception {
            // 此处为属性级的错误日志的处理
            if (e instanceof ConstraintViolationException) {
                log.info("绑定错误日志为:{}", e.getMessage());
                return "请求数据格式错误";
                // 此处为方法级别的错误日志处理
            } else if (e instanceof MethodArgumentNotValidException) {
                log.info("方法级的绑定错误日志为:{}", e.getMessage());
                return "请求数据格式错误";
                // 此处为全局错误日志的处理
            } else {
                log.info("错误日志为:{}", e.getMessage());
                return "全局异常错误给捕获了!";
            }
        }
    
    
    }
    
    

    这时候我们需要在account-server的service方法中抛出运行时异常,然后我们直接访问:http://localhost:8180/order/create?userId=1&productId=1&count=10&money=100,然后我们发现我们的事务实现了回滚了,这就达到了我们想要的效果。

    展开全文
  • } @GlobalTransactional在synchronousDataRelation方法上开启全局事务 resourceService.synchronousDataRelation(schemeSyncVo) 调用Feign接口,在资源微服务中添加数据同步关系(insert) changeDemandStatus私有...

    1.问题描述

    开启全局事务demo:

    /**
     * @Description: 同步数据
     * @Param: [schemeSyncVo]
     * @return: com.vulcan.base.domain.R<java.lang.Boolean>
     * @Author: Lvlin.Lou
     * @Date: 2029/9/16 10:59
     */
    @GlobalTransactional
    @Transactional
    @Override
    public R<Boolean> synchronousDataRelation(SchemeSyncVo schemeSyncVo) {
        resourceService.synchronousDataRelation(schemeSyncVo);
        changeDemandStatus(schemeSyncVo.getUserDemandId(),IntegerUtils.ONE,IntegerUtils.ONE);
        return R.ok(Boolean.TRUE);
    }
    • @GlobalTransactional在synchronousDataRelation方法上开启全局事务

    • resourceService.synchronousDataRelation(schemeSyncVo) 调用Feign接口,在资源微服务中添加数据同步关系(insert)

    • changeDemandStatus私有方法在项目微服务中修改需求状态(update)

    • 无异常全局提交没有问题

    • changeDemandStatus 内有异常 全局回滚没有问题

    • resourceService.synchronousDataRelation(schemeSyncVo)内抛出异常,调用方ch

    展开全文
  • 最近系统中准备使用seata作为分布式事务的工具,但是遇到了个很棘手的问题,正常的service中报错是没有什么问题的,事务都可以进行正常的回滚,但是一旦feign报错,便会自动降级,seata便无法捕获异常。 根据上面的...
  • https://note.youdao.com/s/P9mL0BKi
  • // 我的调用方式是RPC+feign跨服务调用 cn.jbone.common.rpc.Result<Map<String, Object>> data= apiFeign.addData(RootContext.getXID()); log.info("------tagTree---------={}",tagTree); if(data== null){ log....
  • feign分布式事务

    千次阅读 2019-12-19 20:57:29
    微服务中,某事务内通过feign调用多个api,但Transcational注解的事务只对本服务的流程有效,feign调用的接口不会回滚。为使feign调用目标参与事务,需使用分布式锁。 二 结构 原有结构:注册中心、调用者、被调用...
  • 在微服务场景中,通常会有**很多层**的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。...很显然,本文只会讲解`hystrix`和Feign的集成使用,毕竟同根的产品,融合起来会更加的简单高效些。
  • 排查seata分布式事务没有回滚问题

    千次阅读 2020-10-20 15:31:16
    问题:我这边用feign三个服务调用链,seata的TA模式下,发现有个事务没有回滚。 解决方案:排查数据源代理或xid传递 不回滚的分支在这个类,这个函数打断点。 idea双击shift,搜索ExecuteTemplate 记得打勾 .....
  • 使用feign调用远程方法并开启熔断,熔断开启后txlcn的回滚失效,发起方A通过feign调用参与方B(删除操作)、C(添加操作),其中B发生异常能正常回滚,C无异常直接正常执行不参与回滚 事务发起方有关配置如下: ...
  • seata事务无法回滚情况

    千次阅读 2021-04-21 14:04:50
    这里提供两种导致seata事务无法回滚情况的解决方案,当然主要归功于前人留下的宝贵经验。 一、使用@RestControllerAdvice全局异常捕获 使用AOP手动开启全局事务并进行回滚 @Aspect @Component @Slf4j public ...
  • feign 调用失败

    2021-03-28 20:08:06
    目录报错信息:No Feign Client for loadBalancing defined解决方案一:在 spring-cloud 组件中加入spring-cloud-loadbalancer依赖 。在 spring-cloud-alibaba 组件的nacos中排除ribbon依赖解决方案二:降低 spring ...
  • Spring mock测试 回滚数据库

    千次阅读 2017-10-26 17:17:52
    今天在做Spring mock单元测试时,发现如果想要在测试结束后自动回滚数据库只需要在测试类或者方法上打上@Transactional注解即可,而使用Rollback无效。
  • spring cloud使用Feign

    2021-04-30 14:12:52
    feign远程调用组件 Feign是Netflix开发的一个轻量级RESTful的HTTP服务客户端(用它来发起请求,远程调用的),是以 Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用,Feign被 广泛...
  • @Transactional 事务回滚   Spring的AOP事务管理默认是针对unchecked exception回滚(运行期异常,Runtime Exception)。 unchecked ,就是不用手工写try catch的exception   Exception作为基类,下面还分...
  • Feign源码解析之使用Hystrix

    千次阅读 2018-11-03 19:52:57
    上一篇文章讲解了在springcloud项目中feign代理类和feign方法的处理逻辑,在实际项目中,feign经常和hystrix一起使用。hystrix是一种熔断机制,当某个时间单位内错误次数达到一定比例,hystrix会认为服务出现故障,...
  • Feign调用首次失败问题

    千次阅读 2019-12-02 11:03:11
    原文地址:Feign调用首次失败问题||关于feign第一次访问接口失败问题 springcloud中Feign调用常见问题 一、Feign调用首次失败问题 1、Feign简介: Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,294
精华内容 917
关键字:

feign回滚