1、什么情况下会产生分布式事务问题?项目哪些模块涉及到了分布式事务?

—多服务多数据源
—存在增删改的远程调用
88f97d0c10605067a710da827bf00a2.png

项目中分布式事务场景演示:
dd90e7aab5ddbd2897a1b21c17de73e.png
项目中,保存品牌信息,则需远程通过RPC调用文件服务,保存品牌得logo,当保存品牌成功,修改品牌附件信息失败,则缺少附件信息,整个事务无法回滚。

2、seata基础概念及工作原理?

2.1基本概念:

  • TC(Transaction Coordinator) - 事务协调者 【Seata server】

维护全局和分支事务的状态,驱动全局事务提交或回滚(TM之间的协调者)。

  • TM(Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM(Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
e615635f15a2960de6335e382340c32.png

2.2工作流程:

1、TC:启动seata-server,读取配置信息;
2、TM:开启全局事务,生成全局事务id XID,提交给TC;
3、TC:将全局事务XID存入全局事务表中(seata在数据库中有三张表分别是:全局事务表、分支事务表、全局锁表);
4、TC:携带XID远程调用服务提供方RM;
5、RM:携带XID,将分支事务注册到TC;
6、TC:将分支事务保存到分支事务表中(全局事务和分支事务是一对多的关系,所以在分支事务表中保存全局事务XID);
7、TC:发送成功执行的通知给TM,开始执行全局事务;
8、TC:接收TM和RM提交的执行结果,都成功则提交;有一失败则回滚;

2.3工作原理:

e080224d019eafa1fecb63b2c5cb859.png
使用前提: 1. 数据库必须是支持事务的关系型数据库
2. 必须是java项目,并且用JDBC去访问数据库

@GlobalTransactional 标记的方法说明开启了全局事务,seata会为该方法准备一个拦截器
当该方法被调用时,拦截器中 会向TC端 注册一个全局事务信息(xid)
注册好全局事务后,开始执行每个分支事务:
整体流程分为两个阶段;
1. 执行 每一个分支事务
seata为datasource创建了代理对象,每个服务中操作数据库的方法执行时会创建分支事务
执行分支事务时:
seata会先解析要执行的sql语句 生成前置镜像 ==> 执行sql ==> 生成后置镜像 ,将镜像内容存入undolog日志中, 分支事务执行完毕
2. 根据第一阶段结果,提交 或 回滚
如果所有的分支事务都执行成功, 说明全局事务成功,异步的删除undolog日志即可
如果有任何一个环节失败, 根据undolog日志进行事务回滚
回滚时: 会判断当前数据内容和后置镜像是否一致,一致回滚;不一致,就一直重试

2.4分布式事务XID传递原理?

SeataHandlerInterceptor实现了HandlerInterceptor,springMVC会在Controller方法调用之前拿到所有注册到容器中的拦截器链去执行其preHandle()方法,将xid绑定到Root上下文中所以全局事务开启时,是由TM来发起的

  • 依赖seata-spring-boot-starter,支持yml配置
  • 依赖spring-cloud-starter-alibaba-seata,内部集成了seata,并实现了xid传递
  • image.png ```plsql /**

    • @ClassName SeataWebMvcConfig.java
    • @Description webMvc高级配置 */ @Configuration public class SeataWebMvcConfig extends WebMvcConfig {

      /*

      • @description 解决XID传递问题【重要】
      • @return
      • @return: com.alibaba.cloud.seata.web.SeataHandlerInterceptor */ @Bean public SeataHandlerInterceptor seataHandlerInterceptor(){ return new SeataHandlerInterceptor(); }

      /**

      • @Description 拦截器 / @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); registry.addInterceptor(seataHandlerInterceptor()).addPathPatterns(“/*“); }

public class SeataHandlerInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(SeataHandlerInterceptor.class);

  1. public SeataHandlerInterceptor() {
  2. }
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  4. String xid = RootContext.getXID();
  5. String rpcXid = request.getHeader("TX_XID");
  6. if (log.isDebugEnabled()) {
  7. log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);
  8. }
  9. if (StringUtils.isBlank(xid) && rpcXid != null) {
  10. RootContext.bind(rpcXid);
  11. if (log.isDebugEnabled()) {
  12. log.debug("bind {} to RootContext", rpcXid);
  13. }
  14. }
  15. return true;
  16. }

```

3、seata 是否会出现脏读问题?

默认 会出现脏读,因为每个分支事务 真实提交了数据库的事务
如果不想出现脏读,可以在select语句后加上for update,
seata重写了语法解析, 会通过判断全局锁的方式 将隔离级别提升为 读已提交
—> 性能不好

4、seata 是否会出现脏写问题?

不会,虽然有脏读,但如果另一个事务拿到脏数据想修改,还是需要获取全局锁才可以
day06分布式事务解决 - 图6

5、分布式事务的解决方案?

  • XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
    - TCC模式:最终一致的分阶段事务模式,有业务侵入
    - AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
    - SAGA模式:长事务模式,有业务侵入
    -MQ + 本地消息表: 将一个大的事务,拆分成若干小的环节,通过可靠性的消息 来保证全部执行
    day06分布式事务解决 - 图7

6、简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
  • XA模式强一致;AT模式最终一致