本地事务与分布式事务

本文深入探讨了本地事务与分布式事务的区别和应用场景。从事务的基本性质、隔离级别及其问题出发,详细解释了SpringBoot中的事务管理。接着,文章转向分布式事务,分析了CAP定理和BASE理论,提出不同类型的分布式事务解决方案,如2PC、TCC、消息队列实现的最终一致性。最后,介绍了Seata在分布式事务中的作用和使用流程,以及如何利用RabbitMQ实现可靠消息确保事务最终一致性。
摘要由CSDN通过智能技术生成

本地事务与分布式事务

本地事务

事务的基本性质

事务的概念:事务是逻辑上一组操作,组成这组操作各个逻辑单元,要么一起成功,要么一起失败。

数据库事务的几个特性:原子性(Atomicity)、一致性( Consistency )、隔离性或独立性( lsolation)和持久性(Durabilily),简称就是ACID;

  • 原子性:一系列的操作整体不可拆分,要么同时成功,要么同时失败

  • 一 致性:数据在事务的前后,业务整体一致。

    • 转账。A:1000; B:1000; 转200 事务成功; A: 800 B: 1200
  • 隔离性:事务之间互相隔离。

  • 持久性:一旦事务成功,数据一定会落盘在数据库。

在以往的单体应用中,我们多个业务操作使用同一条连接操作不同的数据表,一旦有异常,我们可以很容易的整体回滚;

image-20200722105825203

Business:我们具体的业分代码
Storage:库存业务代码;扣库存
Order:订单业务代码;保存订单
Account:账号业务代码;减账户余额
比如买东西业务,扣库存,下订单,账户扣款,是一个整体;必须同时成功或者失败一个事务开始,代表以下的所有操作都在同一个连接里面;

事务的隔离级别

概念

  • READ UNCOMMITTED (读未提交)
    该隔离级别的事务会读到其它未提交事务的数据,此现象也称之为脏读
  • READ COMMITTED (读提交)
    一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果,此现象称为不可重复读问题,Oracle 和SQL Server的默认隔离级别。
  • REPEATABLE READ (可重复读)
    该隔离级别是MvSQL默认的隔离级别,在同一个事务里,select的结果是事务开始时时间点的转态,因此,同样的select 操作读到的结果会是一致的, 但是,会有幻读现象。MySQL的InnoDB 引擎可以通过next-key locks 机制(参考下文"行锁的算法"一节)来避免幻读。
  • SERIALIZABLE (序列化)
    在该隔离级别下事务都是串行顺序执行的,MySQL数据库的InnoDB引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。

事务并发引起一些读的问题

概念 解释
脏读 一个事务可以读取另一个事务未提交的数据
不可重复读 一个事务可以读取另一个事务已提交的数据 单条记录前后不匹配
虚读(幻读) 一个事务可以读取另一个事务已提交的数据 读取的数据前后多了点或者少了点

并发写:使用mysql默认的锁机制(独占锁)

解决读问题:设置事务隔离级别,隔离级别越高,性能越低。

一般情况下:脏读是不可允许的,不可重复读和幻读是可以被适当允许的。

image-20200722124920166

基本命令

命令 意思
SELECT @@global.tx_isolation 查看全局事务隔离级别
set global transaction isolation level read committed; 设置全局事务隔离级别
SELECT @@tx_isolation 查看当前会话事务隔离级别
set session transaction isolation level read committed 设置当前会话事务隔离级别
select @@autocommit 查看mysql默认自动提交状态
set autocommit = 0; 设置mysql默认自动提交状态【0不自动提交】
start transaction; 开启一个事务
commit 提交事务
rollback 回滚事务
savepoint tx1 在事务中创建一个保存点
rollback to tx1 回滚到保存点

事务的传播行为

  1. PROPAGATION REQUIRED: 如果当前没有事务,就创建一个新事务, 如果当前存在事务,就加入该事务,该设置是最常用的设置。
  2. PROPAGATION SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
  3. PROPAGATION _MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
  4. PROPAGATION REQUIRES NEW:创建新事务,无论当前存不存在事务,都创建新事务。
  5. PROPAGATION NOT SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. PROPAGATION NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. PROPAGATION _NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION REQUIRED 类似的操作。

最常用的就是:PROPAGATION REQUIREDPROPAGATION REQUIRES NEW

SpringBoot 事务关键点

事务的自动配置

TransactionAutoConfiguration

事务的坑

在同一个类里面,编写两个方法,内部调用的时候,会导致事务设置失效。原因是绕过了动态代理对象,事务使用代理对象来控制的

解决:使用代理对象来调用事务方法

1、引入spring-boot-starter-aop;这个场景启动器引入了aspectjweaver
2、@EnableAspectJAutoProxy(exposeProxy = true);开启aspectj 动态代理功能。以后所有的动态代理都是aspectj创建的(特点:即使没有接口也可以创建动态代理对象;exposeProxy = true 对外暴露代理对象)
3、本类方法互调,获取到本代理对象的方法(通过AopContext获取当前类的代理对象)
  OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
  orderService.b();
 // 同一个对象内事务方法互调失效。原因:绕过了动态代理对象
// 事务使用代理对象来控制的
@Transactional(timeout = 30) // a 事务的所有设置会传播到和他公用一个事务的方法
public void a() {
   
  // b,c做任何设置都没用。都是和a同一个事务
  // this.b(); 没用
  // this.c(); 没用
  OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
  orderService.b();
  orderService.c();
  //        bService.b(); // a 事务
  //        cService.c(); // 新事物(不回滚)
  int i = 1 / 0;
}

@Transactional(propagation = Propagation.REQUIRED, timeout = 2) // 设置的timeout不管用,因为你使用的事务是a的
public void b() {
   

}

@Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 20) // 管用
public void c() {
   

}

分布式事务

为什么有分布式事务

  • 分布式系统经常出现的异常
  • 机器宕机、网络异常、消息丢失、消息乱序、数据错误、不可靠的TCP、存储数据丢失…
  • 通过异常机制解决多个系统数据库一致性的问题有缺陷。假如其他系统是成功执行的,但是由于业务超时,我们这边认为对方出现异常,本系统的业务就回滚了,但是别的系统没有回滚。(假异常
  • 调用顺序的问题,本系统调用第三方系统成功,我们也感知到成功了,但是我们下面的代码出错了。我们这边能回滚,但是第三方数据已经修改了。(调用多个系统的数据库操作,第一个调用成功,第二个调用失败)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值