分布式事务

1.本地事务

本地事务,就是传统的单机事务,其中必须要满足四个原则

事务及分布式事务 - 图1

  • 原子性
    • 事务中的操作要么全部成功,要么全部失败
  • 一致性
    • 要保证数据库内部完整性约束,声明约束
  • 隔离性
    • 并发事务中,对同一资源的事务不能同时发生
    • 要想实现隔离性,必须在性能上做出取舍
    • 因此数据库提供了四中方案来实现隔离
  • 持久性
    • 对数据库的一切修改将永久保存,无论是否故障

数据库并发事务会带来的问题

  1. 数据丢失
    由于事务a数据更新失败后,数据回滚,导致事务b更新的数据被覆盖掉,造成数据丢失
  2. 脏读
    一个事务a在失败后回滚的时候,另一个事务读取到了a的事务造成了数据不准确,就为脏读(脏读一定要避免)
  3. 不可重复读
    一个事务在读取数据时多次读取到了其他事务提交的事务
  4. 幻读(可重复读)
    一个事物的修改操作,发现新增加了修改的数据

隔离级别:

解决上面带来的问题

  • 读未提交
    • 会导致脏读、不可重复读以及幻读,需要避免
  • 读已提交
    • 可以避免脏读,但依然存在不可重复读以及幻读的问题
  • 可重复读
    • 可以避免脏读、不可重复读,但依然存在幻读的问题
  • 可序列化
    • 解决了脏 读、不可重复读、幻读等问题,但隔离级别越来越高的同时,并发性会越来越低

2.分布式事务

在分布式架构中,一次业务调用 可能横跨多个服务 多个数据库, 传统的数据库事务无法保证数据的一致性,需要通过分布式事务来解决

分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如:

  • 跨数据源的分布式事务
  • 跨服务的分布式事务
  • 综合情况

2.1 CAP理论

分布式系统有三个指标

  • Consistency(一致性)
    • 用户访问分布式系统中的任意节点,得到的数据必须一致
  • Availability(可用性)
    • 用户访问集群中的任意健康节点,必须能得到响应,而不是超时或拒绝。
  • Partition tolerance (分区容错性)
    • 为网络故障或其它原因导致分布式系统中的部分节点与其它节点失去连接,形成独立分区

但是却无法同时做到三个指标

在P一定会出现的情况下,A和C之间只能实现一个

2.2 BASE理论

ASE理论是对CAP的一种解决思路,包含三个思想:

  • Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
  • Soft State(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。
  • Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。

2.3 解决分布式事务的思路

分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理和BASE理论,有两种解决思路:

  • AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。
  • CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。

3.Seata

Seata:alibaba提供的一套开源框架,提供了分布式事务的一站式解决方案

Seata解决分布式事务四种模式:

事务及分布式事务 - 图2

3.1 Seata使用

  1. 部署seata的服务端(TC 事务协调器)
  2. 修改配置 : registry.conf
  3. 配置事务数据库:
  4. 微服务整合seata
    1. 引入seata的依赖
    2. 修改微服务的配置 指定从nacos中 拉取seata服务端的信息
    3. 在事务的发起方法中 添加全局事务注解(@GlobalTransactional)

3.2 Seata工作原理

使用前提:

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

添加@GlobalTransactional

  1. 标记的方法说明开启了全局事务,seata会为该方法准备一个拦截器
  2. 拦截器中 会向TC 注册一个全局事务信息(xid)并执行

3.3 Seata使用问题

seata 是否会出现脏读问题?

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

seata 是否会出现脏写问题?

不会

虽然有脏读,但如果另一个事务拿到脏数据想修改,还是需要获取全局锁才可以

seata能否保证高可用?

可以通过搭建集群来解决