分布式事务

1:数据库事务的四大特性 ACID
    A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。

    C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转100元,转账前和转账后的数据是正确状态这叫一致性,
        如果出现张三转出100元,李四账户没有增加100元这就出现了数据错误,就没有达到一致性。
        
    I(Isolation):隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务运行过程的中间状态。
        通过配置事务隔离级别可以避脏读、重复读等问题。
        
    D(Durability):持久性,事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。数据库事务在实现时会将一次事务涉及的所有操作全部纳
        入到一个不可分割的执行单元,该执行单元中的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚


2:分布式理论
    a):CAP理论
    b):BASE理论

3:解决方案
    a)2PC(两阶段提交)
        准备阶段和提交阶段
    b)解决方案
        XA方案:
            1、需要本地数据库支持XA协议。
            2、资源锁需要等到两个阶段结束才释放,性能较差
        seata方案:
            1、目前提供AT模式(即2PC)及TCC模式的分布式事务解决方案
            它通过对本地关系数据库的分支事务的协调来驱动完成全局事务,是工作
            在应用层的中间件。主要优点是性能较好,且不长时间占用连接资源,它以高效并且对业务0侵入的方式解决微服务场景下面临的分布式事务问题
            
        seata思想:Seata把一个分布式事务理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务
                    达成一致,要么一起成功提交,要么一起失败
            TM:他负责开启一个全局事务,并向TC发起全局提交或全局回滚的命令    
            TC:事务协调器,独立的中间件需要独立部署运行,维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各各分支事务的提交或回滚
            RM:控制分支事务的提交/回滚
            
    c)DTP:分布式事务处理模型
    
    d)小结
        Seata实现2PC要点:
        1、全局事务开始使用 @GlobalTransactional标识 。
        2、每个本地事务方案仍然使用@Transactional标识。
        3、每个数据都需要创建undo_log表,此表是seata保证本地事务一致性的关键。
        
4:分布式事务解决方案之TCC
    TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认
    Confirm、撤销Cancel。Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的
    操作即回滚操作。TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所
    有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若执行失败,TM会进行重试。
    
    需要处理三种异常: 空回滚 幂等 悬挂  解决方案是新建一张分支事务记录表 记录执行过程中的记录
    
    优点: 可以让应用自己定义数据操作的粒度,使得降低锁冲突、提高吞吐量成为可能。
    缺点: 对应用的侵入性非常强
    
5:可靠消息最终一致性
        指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能
        够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。
        
        实现方案: 将消息发送到消息中间件
        
        要解决以下几个问题:
            1>本地事务与消息发送的原子性问题
            事务发起方在本地事务执行成功后消息必须发出去,否则就丢弃消息。即实现本地事务和消息发送的原子性,要么都成功,要么都失败。
            本地事务与消息发送的原子性问题是实现可靠消息最终一致性方案的关键问题
            2>事务参与方接收消息的可靠性
            
            3>消息重复消费的问题
            
        解决方案:
            1>本地消息表
                此方案的核心是通过本地事务保证数据业务操作和消息的一致性,然后通过定时任务将消息发送至消息中间件,
                待确认消息发送给消费方成功再将消息删除。
        
            如何保证消费者一定能消费到消息呢?
            这里可以使用MQ的ack(即消息确认)机制,消费者监听MQ,如果消费者接收到消息并且业务处理完成后向MQ发送ack(即消息确认),
            此时说明消费者正常消费消息完成,MQ将不再向消费者推送消息,否则消费者会不断重试向消费者来发送消息。
            
            
            注意幂等问题
            
            
6:RocketMQ事务消息方案

流程:
1、Producer 发送事务消息
Producer (MQ发送方)发送事务消息至MQ Server,MQ Server将消息状态标记为Prepared(预备状态),注意此时这条消息消费者(MQ订阅方)是无法消费到的。
本例中,Producer 发送 ”增加积分消息“ 到MQ Server。

2、MQ Server回应消息发送成功MQ Server接收到Producer 发送给的消息则回应发送成功表示MQ已接收到消息。

3、Producer 执行本地事务Producer 端执行业务代码逻辑,通过本地数据库事务控制。
本例中,Producer 执行添加用户操作。

4、消息投递
若Producer 本地事务执行成功则自动向MQServer发送commit消息,MQ Server接收到commit消息后将”增加积分消息“ 状态标记为可消费,此时MQ订阅方(积分服务)
即正常消费消息;若Producer 本地事务执行失败则自动向MQServer发送rollback消息,MQ Server接收到rollback消息后 将删除”增加积分消息“ 。

MQ订阅方(积分服务)消费消息,消费成功则向MQ回应ack,否则将重复接收消息。这里ack默认自动回应,即程序执行正常则自动回应ack。
        
如果执行Producer端本地事务过程中,执行端挂掉,或者超时,MQ Server将会不停的询问同组的其他 Producer来获取事务执行状态,这个过程叫事务回查。
MQ Server会根据事务回查结果来决定是否投递消息。

以上主干流程已由RocketMQ实现,对用户侧来说,用户需要分别实现本地事务执行以及本地事务回查方法,因此只需关注本地事务的执行状态即可。


小结:
可靠消息最终一致性就是保证消息从生产方经过消息中间件传递到消费方的一致性,本案例使用了RocketMQ作为消息中间件,RocketMQ主要解决了两个功能:
1、本地事务与消息发送的原子性问题。
2、事务参与方接收消息的可靠性。
可靠消息最终一致性事务适合执行周期长且实时性要求不高的场景。引入消息机制后,同步的事务操作变为基于消
息执行的异步操作, 避免了分布式事务中的同步阻塞操作的影响,并实现了两个服务的解耦。
        
7:分布式事务解决方案之最大努力通知
通过对最大努力通知的理解,采用MQ的ack机制就可以实现最大努力通知
1、发起通知方将通知发给MQ。
使用普通消息机制将通知发给MQ。
注意:如果消息没有发出去可由接收通知方主动请求发起通知方查询业务执行结果。(后边会讲)
2、接收通知方监听 MQ。
3、接收通知方接收消息,业务处理完成回应ack。
4、接收通知方若没有回应ack则MQ会重复通知。
MQ会按照间隔1min、5min、10min、30min、1h、2h、5h、10h的方式,逐步拉大通知间隔 (如果MQ采用
rocketMq,在broker中可进行配置),直到达到通知要求的时间窗口上限。
5、接收通知方可通过消息校对接口来校对消息的一致性。


系统介绍:
1>p2p
P2P金融又叫P2P信贷  意思是:个人对个人
每位P2P平台用户在银行的存管系统内都会有一个独立账号,平台来管理交易,做到资金和交易分开,让P2P平台不能接触到资金,就可以一定程度避免资金被挪用的风险。
  


事务的传播机制: 
1:默认的传播机制。如果当前方法已经有了一个事务,那么调用方法将在该事务中执行;如果当前方法没有事务,那么调用方法将开启一个新的事务。
2:当前方法支持事务,但是如果调用方法没有事务,那么当前方法不会开启事务。
3:表示当前方法必须在一个事务中执行,如果调用方法没有事务,那么将会抛出异常。
4:表示当前方法必须开启一个新的事务,如果调用方法已经有了一个事务,那么该事务将被挂起,当前方法将在新的事务中执行
5:当前方法不应该在事务中执行,如果调用方法有事务,那么该事务将被挂起,当前方法将在没有事务的上下文中执行。
6:当前方法不应该在事务中执行,如果调用方法有事务,那么将会抛出异常
7:当前方法将在一个嵌套的事务中执行,如果调用方法已经有了一个事务,那么当前方法将嵌套在该事务中执行;
    如果调用方法没有事务,那么当前方法将开启一个新的事务。

事务失效
事务失效可能有多种原因,以下是一些常见的情况:

数据库引擎不支持事务:例如,MySQL的MyISAM引擎不支持事务操作,而InnoDB引擎支持。如果使用的存储引擎不支持事务,那么事务操作不会生效。
没有被Spring管理:如果使用了Spring框架,并且注解如@Service或@Transactional的类没有被Spring容器加载为Bean,那么事务管理将不会生效。
方法不是public的:Spring AOP代理机制要求被@Transactional注解的方法必须是public的。如果方法被声明为private、protected或包私有,
那么事务管理将不会生效。
自身调用问题:如果在类内部直接调用带有@Transactional注解的方法,而不是通过外部调用,事务可能不会生效。
异常处理问题:如果异常被捕获而不是抛出,或者@Transactional注解没有指定回滚的异常类型,事务可能不会按照预期回滚。
方法被final修饰:如果一个方法被final修饰,Spring AOP无法生成代理来添加事务功能,因此事务失效。
异步多线程:如果在多线程环境中执行带有@Transactional注解的方法,并且事务管理没有正确配置以支持异步操作,事务可能不会生效。

使用了错误的事务传播机制:不正确配置事务传播行为可能导致事务管理失效。3

总结:确保使用的数据库支持事务、Spring管理的Bean、public方法上的@Transactional注解、正确的异常处理、非final和private方法的使用、以及异步和多线程环境下的正确事务配置,是避免事务失效的关键。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值