一、背景

在我们使用Seata作为分布式事务时,有些时候我们的分布式时候并不是每次都可以成功的,而对于这些失败的分布式事务就需要进行通知。这篇文章简单记录一下如何实现通知。

二、功能实现

  1. 此处模拟邮件通知,但是不真正发送邮件,只是简单记录一个日志。

三、注意事项

1、 假设我们的分布式事务回滚失败,在AT模式中是会锁定表记录数据的。后期需要获取这条记录的全局锁操作,都会失败。

举例:

假设存在如下数据表记录数据

账号 金额
zhangsan 100

zhangsan这条记录参与分布式事务。

  1. 在分布式事务中将 zhangsan 的金额修改成 90.
  2. 另外一个同事,直接操作数据库,将 zhangsan 的记录修改成 80. (此时是可以修改成功的,因为 Seata 是二阶段提交,在第一阶段结束后,会释放记录的本地锁,不释放记录的全局锁)
  3. 接下来继续别的分布式事务操作,但是发生了异常,此时分布式事务会回滚失败,因为 zhangsan 的金额变成了80,和之前的对应不上。
  4. 如果再次对 zhangsan 进行分布式事务操作或者需要获取全局锁的操作,那么都会失败。

四、实现步骤

1、编写一个类实现FailureHandler接口

FailureHandler 的全类名为:io.seata.tm.api.FailureHandler,它有一个默认的实现DefaultFailureHandlerImpl, 此处我们写一个类继承这个类。

package com.huan.seata.handler;

import io.seata.tm.api.DefaultFailureHandlerImpl;
import io.seata.tm.api.GlobalTransaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; /**
* Seata 分布式事物失败的处理
*
* @author huan.fu 2021/10/8 - 下午1:51
*/
@Component("failureHandler")
@Slf4j
public class EmailSeataFailureHandler extends DefaultFailureHandlerImpl { @Override
public void onBeginFailure(GlobalTransaction tx, Throwable cause) {
super.onBeginFailure(tx, cause);
log.warn("邮件通知:分布式事物出现异常:[onBeginFailure],xid:[{}]", tx.getXid());
} @Override
public void onCommitFailure(GlobalTransaction tx, Throwable cause) {
super.onCommitFailure(tx, cause);
log.warn("邮件通知:分布式事物出现异常:[onCommitFailure],xid:[{}]", tx.getXid());
} @Override
public void onRollbackFailure(GlobalTransaction tx, Throwable originalException) {
super.onRollbackFailure(tx, originalException);
log.warn("邮件通知:分布式事物出现异常:[onRollbackFailure],xid:[{}]", tx.getXid());
} @Override
public void onRollbackRetrying(GlobalTransaction tx, Throwable originalException) {
super.onRollbackRetrying(tx, originalException);
log.warn("邮件通知:分布式事物出现异常:[onRollbackRetrying],xid:[{}]", tx.getXid());
}
}

2、加入到Spring中的BeanName的值

在测试的时候发现FailureHandler加入到Spring中的beanName必须是failureHandler,否则报错,是seata的自动配置中如下代码决定的。

BEAN_NAME_FAILURE_HANDLER 常量的值为 failureHandler


/**
* 源码
* The type Seata auto configuration
*/
@ConditionalOnProperty(prefix = SEATA_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class SeataAutoConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(SeataAutoConfiguration.class); @Bean(BEAN_NAME_FAILURE_HANDLER)
@ConditionalOnMissingBean(FailureHandler.class)
public FailureHandler failureHandler() {
return new DefaultFailureHandlerImpl();
} @Bean
@DependsOn({BEAN_NAME_SPRING_APPLICATION_CONTEXT_PROVIDER, BEAN_NAME_FAILURE_HANDLER})
@ConditionalOnMissingBean(GlobalTransactionScanner.class)
public GlobalTransactionScanner globalTransactionScanner(SeataProperties seataProperties, FailureHandler failureHandler) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Automatically configure Seata");
}
return new GlobalTransactionScanner(seataProperties.getApplicationId(), seataProperties.getTxServiceGroup(), failureHandler);
} }

五、测试

访问curl -X GET http://localhost:50027/createOrder\?accountId\=1\&amount\=10\&hasException\=true,然后手动打断点,修改数据库数据,使数据不一致,然后代码跑出异常,此处回滚失败,因为undo_log表中的数据对不起来。

六、完整代码

https://gitee.com/huan1993/spring-cloud-parent/tree/master/seata/seata-springboot-failure-handler

Seata分布式事务失败通知的更多相关文章

  1. Dubbo学习系列之十五(Seata分布式事务方案TCC模式)

    上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...

  2. SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表

    读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能.也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器:第二台数据库服务器,主要进行读的操作. 目前有多种方式实现读写分离,一种 ...

  3. Seata–分布式事务

    10.1 分布式事务基础 10.1.1 事务 事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销.简单地说,事务提供一种"要 ...

  4. 5-4 Seata 分布式事务管理

    下载Seata https://github.com/seata/seata/releases https://github.com/seata/seata/releases/download/v1. ...

  5. Dubbo学习系列之十四(Seata分布式事务方案AT模式)

    一直说写有关最新技术的文章,但前面似乎都有点偏了,只能说算主流技术,今天这个主题,我觉得应该名副其实.分布式微服务的深水区并不是单个微服务的设计,而是服务间的数据一致性问题!解决了这个问题,才算是把分 ...

  6. SEATA 分布式事务入门DEMO

    Simple Extensible Autonomous Transacation Architecture,seata是简单的.可扩展.自主性高的分布式架构 SEATA Server Configu ...

  7. spring boot:shardingsphere+druid多数据源整合seata分布式事务(spring boot 2.3.3)

    一,为什么要给shardingsphere配置多数据源? 1,shardingjdbc默认接管了所有的数据源, 如果我们有多个非分表的库时,则最多只能设置一个为默认数据库, 其他的非分表数据库不能访问 ...

  8. spring boot:shardingsphere+druid整合seata分布式事务(spring boot 2.3.3)

    一,shardingshpere为什么要整合seata? 分库分表是数据库扩展中最常用的处理方法, shardingshpere作为使用最广泛的分表中间件, 如果不支持分布式事务,则它的数据一致性就会 ...

  9. Seata分布式事务框架Sample

    前言 阿里官方给出了seata-sample地址,官方自己也对Sample提供了很多类型,可以查看学习. 我这里选择演示SpringBoot+MyBatis. 该聚合工程共包括5个module: sb ...

随机推荐

  1. Vue element keyup.enter失效不起作用

    解决方式一 添加按键修饰符@keyup.enter.native 解决方式二 把事件绑定到父元素(外框),需注意多个input问题 <div @keyup.enter="login&q ...

  2. Python - 虚拟环境 venv

    什么是虚拟环境 这是 Python 3.3 的新特性:https://www.python.org/dev/peps/pep-0405/ 假设自己电脑主机的 Python 环境称为系统环境,而默认情况 ...

  3. python库--jieba(中文分词)

    import jieba 精确模式,试图将句子最精确地切开,适合文本分析:全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义:搜索引擎模式,在精确模式的基础上,对长词再次切 ...

  4. Tars | 第8篇 TarsJava Subset最终代码的执行流程与原理分析

    目录 前言 1. SubsetConf配置项的结构 1.1 SubsetConf 1.2 RatioConfig 1.3 KeyConfig 1.4 KeyRoute 1.5 SubsetConf的结 ...

  5. go中如果想要实现别人写的接口,如何保证确实实现了那个接口而不是错过了什么?

    在类型的实现方法上定义通用代码指令 var _ 要实现的接口  = (receiver类型)(nil) 比如要定义一个web处理程序 type  handler_def struct{} var _ ...

  6. Redis核心原理与实践--列表实现原理之quicklist结构

    在上一篇文章<Redis列表实现原理之ziplist结构>,我们分析了ziplist结构如何使用一块完整的内存存储列表数据. 同时也提出了一个问题:如果链表很长,ziplist中每次插入或 ...

  7. CentOS8部署tftp

    tftp:简单文本传输协议,而ftp:文本传输协议.可以把tftp看成是ftp的精简版.tftp用于免登录传输小文件,tftp服务端监听在udp协议的69端口tftp简单的工作原理: tftp服务端与 ...

  8. Ts基本数据类型

    TS的基本数据类型 string let str : string str = 1 //报错 会提示num是字符串 不是数字 str = 'test' //正确 //拼接字符串 let str2 : ...

  9. 猪齿鱼 SaaS 版效能平台发布

    ​日前,猪齿鱼Choerodon全场景效能平台Saas版发布,提供体系化方法论和协作.测试.DevOps及容器工具,帮助企业拉通需求.设计.开发.部署.测试和运营流程,一站式提高管理效率和质量.从团队 ...

  10. PHP的内置WEB服务器

    在很多时候,我们需要简单的运行一个小 demo 来验证一些代码或者轮子是否可用,是否可以运行起来,但是去配 nginx 或者 apache 都很麻烦,其实,PHP CLI 已经提供了一个简单的测试服务 ...