一、MySQL事务

99 阅读14分钟

1、事务的基本概念

1》事务特性:

原子性:

一致性:

隔离性:

持久性:

2》事务类型

3》本地事务

2、MySQL事务基础

1》事务隔离级别:

2》锁分类:

3》InnoDB中的MVCC原理

3、MySQL事务的实现原理

1》Redo Log

2》Undo Log

3》Binlog

二、Spring事务

1、Spring事务原理

Spring事务极大的简化了对于数据库事务的管理操作。通过 @Transactional 注解实现对数据库事务的管理,不必手动开启、提交、回滚事务;Spring在启动创建bean的时候会扫描带有@Transactional的方法,并为其生成代理对象,注入注解带有的参数,在代理对象中处理相应的事务。

2、Spring事务回滚规则

@Transactional(rollbancFor=XXXException.class)

3、Spring三大事务

1、PlantformTransactionManager

Spring提供了多种事务管理器接口,例如PlantformTransactionManager,通过这个接口将事务管理职责委托给了持久化框架:MyBatis..

2、TransactionDefinition接口

定义了与事务相关的方法,表示事务属性常量信息

 public interface TransactionDefinition {
     .....
 }
3、TransactionStatus接口

该接口主要存储事务执行状态,同时有一些接口用来判断或读取事务状态信息

 public interface TransactionStatus extends SavepointManager, Flushable {
    ...
 }

4、Spring事务隔离级别

5种隔离级别。

Spring事务隔离级别比数据库事务隔离级别多一个default

1) DEFAULT (默认) 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

2) READ_UNCOMMITTED (读未提交) 这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

3) READ_COMMITTED (读已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

4) REPEATABLE_READ (可重复读) 这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

5) SERIALIZABLE(串行化) 这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

5、Spring事务传播类型

事务传播类型包含7种,包含在Propagation枚举类中。设置方式@Transactional(propagtion = Propagation.REQUIRED)

1) required(默认属性)

Spring中默认传播类型

如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。

2) Mandatory 支持当前事务,如果当前没有事务,就抛出异常。

3) Never 以非事务方式执行,如果当前存在事务,则抛出异常。

4) Not_supports 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

5) requires_new 新建事务,如果当前存在事务,把当前事务挂起。

6) Supports 支持当前事务,如果当前没有事务,就以非事务方式执行。

7) Nested 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

常用的类型:required、not_supports、requires_new

实践场景:

前提----内外方法在不同类里

① 外部方法无事务注解,内部方法添加REQUIRED事务传播类型时。内部方法抛出异常,内部方法执行失败不会影响外部方法的执行,外部方法执行成功。

② 外部方法添加REQUIRED事务传播类型,内部方法无事务注解。内部方法抛出异常,会导致外部事务回滚。

③ 内外部方法都添加REQUIRED事务传播类型时。内部方法抛出异常,会导致外部事务回滚。

④ 外部方法添加REQUIRED,内部方法添加NOT_SUPPORTED。内部方法抛异常,外部执行成功,事务会提交;外部方法执行失败,事务会回滚。

⑤ 外部方法添加REQUIRED,内部方法添加REQUIRES_NEW。

内部抛出异常,内外方法都执行失败,事务回滚。

异常在外部方法尾部时,内部方法执行失败,内外执行失败,事务回滚;内部方法执行成功,事务提交

异常在外部方法尾部时,内外方法在同一个类中。内部抛出异常,内外执行失败,事务回滚

6、事务失效场景

  1. 事务所在的类没有被Spring管理
  2. 方法没有被public修饰
  3. 同一个类中方法调用
  4. 不正确的使用try-catch捕获了异常
  5. 标注错误的异常类型,Spring中默认的事务异常类型是RuntimeException

三、分布式系统演进

1、架构演变

image.png

单体服务 -> 垂直架构 -> SOA架构 -> 微服务架构

SOA架构:

image.png

微服务:

image.png

SOA在垂直架构的基础上,抽离出重叠的功能作为公共的服务,进行规范的、统一的信息交互,解决混乱调用问题。

微服务架构将单一的应用程序拆分为一组小型服务,每个服务都是围绕业务能力进行构建,能够独立开发、测试、部署,服务间采用轻量级的通讯机制。

SOA架构和微服务架构的区别:

SOA架构下会多一层API服务,API服务调用多个独立的子服务,完成功能的聚合

微服务去中心化,去掉了API层

2、分布式事务场景

① 跨JVM进程。服务与服务之间通过RPC调用

② 跨数据库实例。服务跨数据源访问多个数据库

③ 多个服务访问同一个数据库实例。

3、数据一致性问题

① 多个节点缓存数据不一致问题。缓存的脑裂

② 缓存与数据库数据不一致。

③ 调用时超时。A服务调用B服务超时,B服务数据更新执行成功与否?不确定

④ 数据多副本场景。

4、分布式事务理论

CAP理论:一致性、可用性、分区容忍性

① 一致性:用户对数据的更新操作,要么在所有的数据副本都执行成功,要么在所有副本都是执行失败,数据副本的修改必须是原子性

② 可用性:应用程序访问数据时能够快速响应结果数据;不能出现超时、错误的情况

③ 分区容忍性:主从集群部署在不同的网络节点上,网络通信失败时保证系统扔能对外提供服务

CAP组合:

C:

A:

P:

AP、CP、CA三种组合

AP大部分分布式系统会采用AP方式,舍弃一致性,通过最终一致性保证数据的一致

Base理论:

base理论是AP理论的一个扩展,通过牺牲强一致性获得可用性,保证最终一致性

四、分布式事务解决方案

1、强一致性

强一致性:任何时刻查询参与全局事务的各节点的数据都是一致性的

方案:

1> DTP模型

是一套分布式事务标准,定义实现了分布式事务的规范和API。有3个核心组件:AP、TM、RM。

AP:应用程序。

RM:资源管理器。数据库管理系统或消息服务管理系统。

TM:事务管理器。协调和管理DTP模型中的事务,同时管理资源管理器

2> 2PC模型

两阶段提交协议模型。Prepare阶段、Commit阶段;

image.png

缺点:

同步阻塞。等待事务提交和执行结果都是同步等待

单点故障。事务管理器自身的存在故障时影响资源管理器操作

3> 3PC模型

三阶段提交模型。存在事务管理器和资源管理器

事务执行成功流程:

阶段一:事务管理器向资源管理器发送CanCommit消息;资源管理器向事务管理器返回Yes

阶段二:事务管理器向资源管理器发送PreCommit消息,资源管理器开始执行事务操作,将Undo和Redo写入事务日志;并返回Ack消息

阶段三:事务管理器向资源管理器发送PreCommit消息,资源管理器执行事务提交操作,返回已提交状态

事务执行失败流程:

阶段一:事务管理器向资源管理器发送CanCommit消息;异常资源管理器向事务管理器返回No

阶段二:事务管理器向资源管理器发送Abort消息,资源管理器中断事务操作

阶段三:事务管理器向资源管理器发送doRollBack消息,资源管理器利用Undo log回滚事务

3PC模型解决了2PC模型中的阻塞问题,资源管理器接收不到事务管理器的消息(超时)会自动提交事务,但是会导致数据不一致,提交的事务数据不能再回滚

2、最终一致性

并不要求参与事务的各节点的数据时刻保持一致,允许其存在中间状态,只要一段时间后,能够达到数据的最终一致状态

服务模式:

a、可查询操作

服务操作具有可标识性,业务服务需要提供根据唯一标识查询信息的接口

b、幂等操作

重试调用执行多少次都能输出相同的结果

c、TCC操作

三阶段:1、Try阶段;2、Confirm阶段;3、Cancel阶段

d、可补偿操作

如果数据处于不正常状态,可通过某种方式进行业务补偿,使数据达到一致性

2.1、解决方案
2.1.1、TCC

应用层将一个完整的事务分为三个阶段:Try、Confirm、Cancel。

实现的模式:可查询操作、幂等操作、TCC操作、可补偿操作

TCC需要注意的问题:

1、空回滚问题。调用Try之前服务网络问题,网络回复后回滚执行Cancel方法时,就会出现空回滚;解决办法:使用事务全局ID和分支事务ID记录,执行Try时往分支记录表中插入一条记录,执行Cancel时判断是否存在调用再回滚

2、幂等问题。调用超时或者网络等原因,未知分支事务的执行情况,TCC会有重试机制,重试时容易导致数据不一致问题,需要保证Commit和Cancel阶段的幂等。解决方案:分支事务记录表上需要记录事务的执行状态,执行Commit和Cancel前先判断状态

3、悬挂问题。

image.png

解决办法:

执行Try时判断分支记录表中是否存在全局是武侠Confirm和Cancel的记录操作,有则不执行Try的方法

2.1.2、可靠消息最终一致性

概念:

事务的发起方执行完本地事务之后发出一条消息,事务参与方一定能接收到这条消息并处理成功。消息数据能独立存储,解决系统之间的耦合

基于本地消息表和消息队列中间件两种方式实现。

实现的模式:可查询操作、幂等操作

执行过程:

最重要的是消息确认服务和消息恢复服务。

image.png

需要注意的问题:

a、事务发送方本地执行和发送消息的原子性

b、事务参与方接收消息的可靠性问题

c、事务参与方接收到消息的幂等性问题

2.2.3、最大努力通知型

消息发送方服务,接收方服务,允许消息丢失;事务被动方处理结果不影响主动方的处理结果。

解决方式:

a、主动方设置时间阶梯型通知规则,消息丢失后重试

b、被动方应做到幂等,避免重复消息导致数据不一致

c、达到重试次数后。主动方提供事务状态查询的回查接口供被动方未接收到消息时的查询功能

实现的模式:可查询模式、幂等模式

五、分布式事务原理

1、XA强一致性分布式

2、TCC分布式

一个完整的分布式事务包含:主业务服务(事务发起方)、从业务服务(事务操作方)、TCC管理器

核心原理:

需要将原本的一个事务接口改造成三个不同的事务逻辑。提供Try、Commit、Cancel的操作

三个阶段不同的处理内容:

image.png

在业务系统中设计者三个阶段的时候需要考虑许多问题:

a、发生异常时如何处理?记录一些分布式事务的日志

TCC应用于订单支付的案例:用户下单、产生一笔订单、扣库存、加积分,生成出货单。

Try阶段:

a、订单更新为支付中

b、库存服务。商品的冻结字段中+此次订单商品个数,商品库存数量减去当前订单商品个数

c、积分服务中,订单产生的积分记录到用户积分表中预增加字段

d、仓储服务。出货单状态标记为“未知”

Confirm阶段:

a、订单更新为支付成功

b、库存服务。商品库存数-订单的商品个数,预扣减字段-订单商品个数

c、积分服务中,用户积分表中增加积分

d、仓储服务。出货单状态标记为“已创建”

Cancel阶段:

a、订单更新为支付失败

b、库存服务。预扣减字段-商品个数;商品库存数+订单的商品个数

c、积分服务中,预增加字段-积分数

d、仓储服务。出货单状态标记为“已取消“

TCC分布式事务框架:Hmily。关键技术:

1、AOP切面

2、反射技术。实现Confirm、Cancel阶段的调用

3、持久化技术

4、序列化技术。多服务之间通信

5、定时任务

6、动态代理

3、可靠消息最终一致性

原理:事务发起方执行本地事务成功后发出一条消息,事务参与方接收到事务发起方发送过来的消息,并成功执行本地事务。主要有两点:

1> 事务发起方一定能够将消息发送出去

2> 事务参与方一定能够成功接收到消息

如何保证事务发起方本地事务执行和发送消息的一致性?

1》本地消息表。存放消息的本地消息表和业务表放在一个库里,通过事务操作可实现一致性。但是存储和编码成本高,不可取

2》独立消息服务。消息处理部分独立部署服务,实现分布式事务需要有几个核心服务:可靠消息服务、消息确认服务、消息恢复服务、消息中间件。

image.png

3》RocketMQ事务消息。Producer端的本地事务与消息发送形成一个完整的原子操作

image.png

提供了本地事务监听接口:RocketMQLocalTransactionListener实现了两个方法:

executeLocalTransaction() // MQ回调改方法,返回事务状态

checkLocalTransaction() // 回查本地事务状态

问题:美团的MQ怎么实现的分布式事务消息?

4》如何保证消息发送的一致性?

消息发送方本地事务和消息发送整体的一致性。需要手动实现消息的发送和确认机制。

image.png

5》消息接收一致性

消息中间件向事务接收方投递消息一直失败时,根据指定规则重试,重试扔失败,存储到死信队列中,人工干预

保证消息接收的一致性需:

限制消息重复投递次数;

事务接收方接口幂等;

事务接收方与消息中间件的确认机制;

重试失败消息进入死信队列

6》 消息的可靠性

发送可靠性:发送方部署多份,集群模式;

消息存储可靠性:消息存储的多副本机制

消息消费可靠性:消费方集群模式,幂等机制

4、最大努力通知型

六、分布式事务源码与实战