精华内容
下载资源
问答
  • 事务 | Spring Cloud 分布式事务管理 LCN、GTX、ByteTCC

    万次阅读 多人点赞 2018-03-18 21:03:04
    事务 | Spring Cloud 分布式事务管理 LCN、GTX、ByteTCC 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率. Spring ...

    Spring Cloud 分布式事务管理

    在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率.


    在说微服务的优缺点时,有对比才会更加明显,首先说一下单体式结构

    单体式架构

    在单体式架构中,系统通常采用分层架构模式(MVC),持久化层、表示层,业务逻辑层。架构主要存在以下问题:

    1. 系统内部互相访问,耦合紧密导致难以维护;
    2. 各业务领域需要采用相同的技术栈,难以快速应用新技术(例如使用SSH很难向SSM改造);
    3. 对系统的任何修改都必须整个系统一起重新部署/升级;
    4. 在系统负载增加时,难以进行水平扩展;
    5. 当系统中一处出现问题,会影响整个系统;

    为了克服以上缺点,微服务架构应运而生。微服务,又叫微服务架构。微服务就是一些协同工作的小而自治的服务.

    微服务架构

    优点

    1. 技术异构性

    在不同的服务中,可以使用不同的技术来各自开发,只要保证服务间能相互协作即可

    2. 弹性

    当微服务中的某一个服务不可用时,不会影响整个系统,只会影响相关功能不可用

    3. 扩展

    易于扩展,使用小的多个服务,更加易于扩展新的功能

    4. 简化部署

    某个服务的更新部署,不需要重新部署整个应用

    5. 可组合

    通过组合多个服务,可以提供一些新的功能

    6. 可替代

    因为每个微服务都比较小,重新实现某一个服务或者直接删除该服务都是可操作的

    缺点

    1. 复杂度高

    微服务间通过REST、RPC等形式交互,相对于单体模式,需要考虑被调用方故障、过载、消息丢失等各种异常情况,代码逻辑更加复杂。

    对于微服务间的事务性操作,因为不同的微服务采用了不同的数据库,将无法利用数据库本身的事务机制保证一致性,需要引入二阶段提交等技术。

    同时,在微服务间存在少部分共用功能但又无法提取成微服务时,各个微服务对于这部分功能通常需要重复开发,或至少要做代码复制,以避免微服务间的耦合,增加了开发成本。

    2. 运维复杂

    在采用微服务架构时,系统由多个独立运行的微服务构成,需要一个设计良好的监控系统对各个微服务的运行状态进行监控。运维人员需要对系统有细致的了解才对够更好的运维系统。

    3. 影响性能

    相对于单体架构,微服务的间通过REST、RPC等形式进行交互,通信的时延会受到较大的影响。

    分布式事务的引入

    正如上面所说

    对于微服务间的事务性操作,因为不同的微服务采用了不同的数据库,将无法利用数据库本身的事务机制保证一致性,需要引入二阶段提交等技术。

    在单体项目中,很容易做到事务控制,而在多个服务之间很难实现

    假设服务调用如下:

    这里写图片描述

    A B C D 的事务均在各个服务控制,如何做到,统一协调,保证数据的一致性?

    分布式事务解决方案

    基于XA协议的两阶段提交

    XA是一个分布式事务协议,由提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:
    第一阶段:

    Tuxedo

    第二阶段:
    这里写图片描述

    总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往并发量很高,XA无法满足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

    消息事务+最终一致性

    所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败,开源的RocketMQ就支持这一特性.

    该方案采用最终一致的,牺牲了一致性,换来了性能的大幅度提升。存在造成数据不一致的风险

    TCC编程模式

    所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。

    具体实现

    LCN

    https://github.com/codingapi/tx-lcn

    LCN分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。因此该框架与其他第三方的框架兼容性强,支持所有的关系型数据库事务,支持多数据源,支持与第三方数据库框架一块使用(例如 sharding-jdbc),在使用框架的时候只需要添加分布式事务的注解即可,对业务的侵入性低。LCN框架主要是为微服务框架提供分布式事务的支持,在微服务框架上做了进一步的事务机制优化,在一些负载场景上LCN事务机制要比本地事务机制的性能更好,4.0以后框架开方了插件机制可以让更多的第三方框架支持进来
    

    目前 LCN为 4.1 版本

    主要特点:

    • 支持各种基于spring的db框架
    • 兼容SpringCloud、Dubbo、motan
    • 使用简单,低依赖,代码完全开源
    • 基于切面的强一致性事务框架
    • 高可用,模块可以依赖RPC模块做集群化,TxManager也可以做集群化
    • 支持本地事务和分布式事务共存
    • 支持事务补偿机制,增加事务补偿决策提醒

    采用强一致性方案,事务要不全部成功,要不全部失败,保证了事务的一致性,代码简单,原有项目只需引入相关 jar 包,并在需要参与的事务的方法添加注解即可,节省了代码改造成本.

    Spring Cloud示例:

    添加依赖

    <properties>
       <lcn.last.version>4.1.0</lcn.last.version>
    </properties>
    
    <dependency>
        <groupId>com.codingapi</groupId>
        <artifactId>transaction-springcloud</artifactId>
        <version>${lcn.last.version}</version>
    </dependency>
    
    <dependency>
       <groupId>com.codingapi</groupId>
       <artifactId>tx-plugins-db</artifactId>
       <version>${lcn.last.version}</version>
    </dependency>
    
    

    在需要执行的事务上添加注解

    @Override
    @TxTransaction(isStart = true)
    @Transactional
    public int save() {
    }
    

    其中 @TxTransaction(isStart = true)lcn 事务控制注解,其中isStart = true 表示该方法是事务的发起方例如,服务A 需要调用服务B,服务B 需要调用服务C,此时 服务A为服务发起方,其余为参与方,参与方只需@TxTransaction 即可

    在测试时需要将 事务管理服务启动 txManager, 具体示例参看:https://www.txlcn.org

    ByteTCC

    https://github.com/liuyangming/ByteTCC

    ByteTCC是一个基于TCC(Try/Confirm/Cancel)机制的分布式事务管理器。兼容JTA,可以很好的与EJB、Spring等容器(本文档下文说明中将以Spring容器为例)进行集成。

    ByteTCC特性
    1、支持Spring容器的声明式事务管理;
    2、支持普通事务、TCC事务、业务补偿型事务等事务机制;
    3、支持多数据源、跨应用、跨服务器等分布式事务场景;
    4、支持长事务;
    5、支持dubbo服务框架;
    6、支持spring cloud;

    该实现方式,需要在业务层编写对应的 tcc(Try/Confirm/Cancel) 方法,开发需要一定的成本,同时某些业务可能无法保证数据可回滚

    查看示例:https://github.com/liuyangming/ByteTCC

    参考:

    1. https://github.com/codingapi/tx-lcn
    2. https://github.com/liuyangming/ByteTCC
    3. 微服务设计(Sam Newman)

    如果你喜欢就关注一下吧. 以后会写一下我们公司在使用Spring Cloud 中遇到的问题和一些经验

    这里写图片描述

    下一篇 Spring Cloud 分布式事务管理(二)2pc/3pc
    系列文章
    事务Transaction
    Spring Cloud 分布式事务管理
    Spring Cloud 分布式事务管理(二)2pc/3pc
    谢谢大家阅读和不吝赐教,以后会专门写几篇文章讲述一下数据库事务相关的操作,包括但不限于:事务概念、MySQL事务管理、JDBC事务管理、Spring 事务管理、Hibernate事务管理、多数据源事务管理、分布式事务管理等方面的文章

    展开全文
  • 分布式事务管理

    2018-10-26 16:17:58
     总算完整的学习了一遍事务管理,有些事自己的领悟,大多还是参考现有的很多资料。作为一个知识的搬运工,我把知识做了一个总结,也算对这段时间的学习有个交代。 内容主要是:事务的定义,以及不同架构的事务使用...

    说在前面:

           总算完整的学习了一遍事务管理,有些事自己的领悟,大多还是参考现有的很多资料。作为一个知识的搬运工,我把知识做了一个总结,也算对这段时间的学习有个交代。

    内容主要是:事务的定义,以及不同架构的事务使用。特别是现在微服务架构盛行的时候。对分布式事务起码需要了解

    一、分布式与集群概念

    1.分布式是将不同的业务分布在不同的地方

    2.集群是将几台服务器集中在一起,实现同一业务

    3.分布式中每个节点,都可以做集群

     

    • 服务架构

    传统服务 -----> SOA -----> 微服务架构

     

    功能

    SOA

    微服务

    组件大小

    大块业务逻辑

    单独任务或小块业务逻辑

    耦合

    通常松耦合

    总是松耦合

    公司架构

    任何类型

    小型、专注于功能交叉团队

    管理

    着重中央管理

    着重分散管理

    目标

    确保应用能够交互操作

    执行新功能、快速拓展开发团队

     

    1.SOA特点:

    两个主要角色:服务提供者(Provider)和服务使用者(Consumer)

    系统集成:站在系统的角度,解决企业系统间的通信问题,把原先散乱、无规划的系统间的网状结构,梳理成规整、可治理的系统间星形结构,这一步往往需要引入一些产品,比如ESB、以及技术规范、服务管理规范;这一步解决的核心问题是【有序】

     

    系统的服务化:站在功能的角度,把业务逻辑抽象成 可复用、可组装的服务,通过服务的编排实现业务的 快速再生,目的:把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用;这一步解决的核心问题是【复用】

     

    业务的服务化:站在企业的角度,把企业职能抽象成可复用、可组装的服务;把原先职能化的企业架构转变为服务化的企业架构,进一步提升企业的对外服务能力;“前面两步都是从技术层面来解决系统调用、系统功能复用的问题”。第三步,则是以业务驱动把一个业务单元封装成一项服务。这一步解决的核心问题是【高效】

     

    2.微服务架构

    某种程度上是面向服务的架构SOA继续发展的下一步

        1.通过服务实现组件化

            开发者不再需要协调其它服务部署对本服务的影响。

        2.按业务能力来划分服务和开发团队

            开发者可以自由选择开发技术,提供 API 服务

        3.去中心化

            每个微服务有自己私有的数据库持久化业务数据

            每个微服务只能访问自己的数据库,而不能访问其它服务的数据库

            某些业务场景下,需要在一个事务中更新多个数据库。这种情况也不能直接访问其 它微服务的数据库,而是通过对于微服务进行操作。

            数据的去中心化,进一步降低了微服务之间的耦合度,不同服务可以采用不同的数 据库技术(SQL、NoSQL等)。在复杂的业务场景下,如果包含多个微服务,通常在客户 端或者中间层(网关)处理。

        4.基础设施自动化(devops、自动化部署)

            Java EE部署架构,通过展现层打包WARs,业务层划分到JARs最后部署为EAR一 个大包,而微服务则打开了这个黑盒子,把应用拆分成为一个一个的单个服务,应用 Docker技术,不依赖任何服务器和数据模型,是一个全栈应用,可以通过自动化方式 独立部署,每个服务运行在自己的进程中,通过轻量的通讯机制联系,经常是基于HTTP 资源API,这些服务基于业务能力构建,能实现集中化管理(因为服务太多啦,不集中 管理就无法DevOps啦)。

     

    三、事务

    1.柔性事务VS刚性事务

    本地事务采用刚性事务, JDBC(单库的事务)

    分布式事务使用柔性事务 JTA(多库的事务)

     

    刚性事务是指严格遵循ACID原则的事务, 例如单机环境下的数据库事务

    柔性事务是指遵循BASE理论的事务, 通常用在分布式环境中, 常见的实现方式有:

    两阶段提交(2PC), TCC补偿型提交, 基于消息的异步确保型, 最大努力通知型.

    2.事务相关定义

    ACID(Atomicity,Consistency,Isolation,Durability)

    Atomicity原子性:一个事务中所有操作都必须全部完成,要么全部不完成。

    Consistency一致性. 在事务开始或结束时,数据库应该在一致状态。

    Isolation隔离层. 事务将假定只有它自己在操作数据库,彼此不知晓。

    Durability. 一旦事务完成,就不能返回。

     

    CAP帽子理论: CAP(Consistency, Availability, Partition Tolerance)

    Consistency(一致性), 数据一致更新,所有数据变动都是同步的

    Availability(可用性), 好的响应性能

    Partition tolerance(分区容忍性) 可靠性

     

    BASE思想: BASE(Basically avaliable, soft state, eventually consistent):

    是分布式事务实现的一种理论标准,分布式系统的一致性和可用性不能兼得的问题

     

    BASE模型反ACID模型,完全不同ACID模型,牺牲高一致性,获得可用性或可靠性:

    Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库)

    Soft state软状态 状态可以有一段时间不同步,异步。

    Eventually consistent最终一致,最终数据是一致的就可以了,而不是时时高一致。

     

    3.刚性事务:

    事务的定义:事务表示一个由一系列的数据库操作组成的不可分割的逻辑单位,其中的操作要么全做要么全都不做。

    事务的特性 ACID(Atomicity,Consistency,Isolation,Durability)

    1、原子性:同一个事务的操作要么全部成功执行,要么全部撤消

    2、隔离性:事务的所有操作不会被其它事务干扰

    3、一致性:在操作过程中不会破坏数据的完整性

    4、持久性:一旦事务完成了,那么事务对数据所做的变更就完全保存在了数据库 中

     

     

    4个隔离级别

    1:默认的隔离级别,同数据库一样的,如果不做特别设置,

    mysql默认的是可重复读,而oracle默认的是读提交

    2:读未提交,即一个事务可以读取另外一个事务中未提交的数据,

    即脏读数据存在,性能最好,但是没啥用

    3:读提交,即一个事务只能读取到另一个事务提交后的数据,

    oracle数据库默认隔离级别;存在不可重复读问题,即交叉事务出现,

    A事务两次读取数据可能会读到B事务提交的修改后的数据,

    即在同一个事务中读到了不同的数据,也叫不可重复读

    4:可重复读,即一个事务只能读取到在次事务之前提交的数据,而之后提交不能 读取到,不管对方的事务是否提交都读取不到,mysql默认的隔离级别。

    此隔离级别有可能会遇到幻读现象,但是mysql 基于innodb引擎实现的数据 库已经通过多版本控制解决了此问题,所以可以不考虑了。

     

    7个传播方式

    int PROPAGATION_REQUIRED = 0;  //事务传播级别1:当前如果有事务,

    Spring就会使用该事务;否则会开始一个新事务;(这也是默认设置和定义)

    int PROPAGATION_SUPPORTS = 1;//事务传播级别2:如果有事务,

    Spring就会使用该事务;否则不会开始一个新事务

    int PROPAGATION_MANDATORY = 2;  //事务传播级别3:当前如果有事务,

    Spring就会使用该事务;否则会因为没有事务而抛出异常

    int PROPAGATION_REQUIRES_NEW = 3;//事务传播级别4:总是要开启一个新事务。

    如果当前已经有事务,则将已有事务挂起

    int PROPAGATION_NOT_SUPPORTED = 4;//事务传播级别5:

    代码总是在非事务环境下执行,如果当前有事务,则将已有事务挂起,再执行 代码,之后恢复事务

    int PROPAGATION_NEVER = 5; //事务传播级别6:绝对不允许代码在事务中执行。

    如果当前运行环境有事务存在,则直接抛出异常,结束运行

    int PROPAGATION_NESTED = 6;//事务传播级别7:该级别支持嵌套事务执行。如果 没有父事务存在,那么执行情况与PROPAGATION_REQUIRED一样;

    典型的应用是批量数据入库,开启父事务对一批数据入库,而对于每条入库的 数据都有一个子事务对应,

    那么当所有的子事务成功,父事务提交,才算成功,否则,就都失败。

     

    JDBC 注解/编程式

    1.注解 @Transaction

    推荐使用注解

    2.编程式

    TransactionDefinition def = new DefaultTransactionDefinition();

    TransactionStatus status = transactionManager.getTransaction(def);

    try{

    业务逻辑。。。

    transactionManager.commit(status);//提交

    }catch(Exception e){

    transactionManager.rollback(status);//回滚

    throw e;

    }

     

    1. 柔性事务:

    https://blog.csdn.net/u010425776/article/details/79516298

    1. 分布式事务处理种类

    1)、两阶段提交(2PC)型

    对应技术上的XA、JTA/JTS

    2)、事务补偿型(TCC事务)

    3)、异步确保型

    4)、最大努力型(消息队列)

    2.分布式事务管理多数据库实现方式:

    1. 基于XA协议的两阶段提交方案

    交易中间件与数据库通过 XA 接口规范,使用两阶段提交来完成一个全局事务, XA 规范的基础是两阶段提交协议。

    第一阶段是表决阶段,所有参与者都将本事务能否成功的信息反馈发给协调者;第二阶段是执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地在所有分支上提交或者回滚。

    两阶段提交方案应用非常广泛,几乎所有商业OLTP数据库都支持XA协议。但是两阶段提交方案锁定资源时间长,对性能影响很大,基本不适合解决微服务事务问题

     

    1. TCC方案

    在电商、金融领域落地较多。TCC方案其实是两阶段提交的一种改进。其将整个业务逻辑的每个分支显式的分成了Try、Confirm、Cancel三个操作。Try部分完成业务的准备工作,confirm部分完成业务的提交,cancel部分完成事务的回滚。基本原理如下图所示。

    事务开始时,业务应用会向事务协调器注册启动事务。之后业务应用会调用所有服务的try接口,完成一阶段准备。之后事务协调器会根据try接口返回情况,决定调用confirm接口或者cancel接口。如果接口调用失败,会进行重试。

    TCC方案让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。 当然TCC方案也有不足之处,集中表现在以下两个方面:

    对应用的侵入性强。业务逻辑的每个分支都需要实现try、confirm、cancel三 个操作,应用侵入性较强,改造成本高。

    实现难度较大。需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm和cancel接口必须实现幂等。

    上述原因导致TCC方案大多被研发实力较强、有迫切需求的大公司所采用。微服务倡导服务的轻量化、易部署,而TCC方案中很多事务的处理逻辑需要应用自己编码实现,复杂且开发量大。

    1. 基于消息的最终一致性方案

    通过消息中间件保证上、下游应用数据操作的一致性

    。基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么两者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操作。

    消息方案从本质上讲是将分布式事务转换为两个本地事务,然后依靠下游业务的重试机制达到最终一致性。基于消息的最终一致性方案对应用侵入性也很高,应用需要进行大量业务改造,成本较高。

     

    1. 异步确保型

     

     

     

     

    1. 案例解析
    1. 基于支付系统真实业务场景进行具体问题实现和详细讲解分布式事务

              https://www.oschina.net/question/3573545_2282562

    展开全文
  • 分布式事务管理分布式事务管理的第六章。内有参考实现
  • CH6 分布式事务管理

    2013-11-08 12:06:49
    6 1 事务的基本概念 6 2 分布式事务 6 3 分布式事务的提交协议 6 4 分布式事务管理的实现 6 5 两段提交协议 2PC 的实现方法 6 6 非阻塞分布式事务提交协议
  • springboot分布式事务管理(atomikos)

    万次阅读 热门讨论 2017-09-28 16:15:00
    最近公司有用到分布式事务管理,结合公司和我上网查询的一些资料,特来梳理一下我思路。 本篇文章使用时(atomikos)来进行springboot的分布式事务管理 1.引用jta-atomikos架包 <dependency> <...

    需要学习视频资料请加qq 1686763368 

    最近公司有用到分布式事务管理,结合公司和我上网查询的一些资料,特来梳理一下我思路。

    本篇文章使用时(atomikos)来进行springboot的分布式事务管理

    1.引用jta-atomikos架包

     

    	<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-jta-atomikos</artifactId>
    		</dependency>

     

     

     

     

     

    2,首先配置数据源,因为是要演示分布式事务管理所以要配置多个数据源(2个)

    # Mysql 1
    mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test1.username = root
    mysql.datasource.test1.password = root
    mysql.datasource.test1.minPoolSize = 3
    mysql.datasource.test1.maxPoolSize = 25
    mysql.datasource.test1.maxLifetime = 20000
    mysql.datasource.test1.borrowConnectionTimeout = 30
    mysql.datasource.test1.loginTimeout = 30
    mysql.datasource.test1.maintenanceInterval = 60
    mysql.datasource.test1.maxIdleTime = 60
    mysql.datasource.test1.testQuery = select 1
    
    
    # Mysql 2
    mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test2.username =root
    mysql.datasource.test2.password =root
    
    mysql.datasource.test2.minPoolSize = 3
    mysql.datasource.test2.maxPoolSize = 25
    mysql.datasource.test2.maxLifetime = 20000
    mysql.datasource.test2.borrowConnectionTimeout = 30
    mysql.datasource.test2.loginTimeout = 30
    mysql.datasource.test2.maintenanceInterval = 60
    mysql.datasource.test2.maxIdleTime = 60
    mysql.datasource.test2.testQuery = select 1
    

     

     

    3,配置读取数据库属性文件

    DBConfig1.java

     

    package com.itmayiedu.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    @ConfigurationProperties(prefix = "mysql.datasource.test1")
    public class DBConfig1 {
    
    	private String url;
    	private String username;
    	private String password;
    	private int minPoolSize;
    	private int maxPoolSize;
    	private int maxLifetime;
    	private int borrowConnectionTimeout;
    	private int loginTimeout;
    	private int maintenanceInterval;
    	private int maxIdleTime;
    	private String testQuery;
    	public String getUrl() {
    		return url;
    	}
    	public void setUrl(String url) {
    		this.url = url;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public int getMinPoolSize() {
    		return minPoolSize;
    	}
    	public void setMinPoolSize(int minPoolSize) {
    		this.minPoolSize = minPoolSize;
    	}
    	public int getMaxPoolSize() {
    		return maxPoolSize;
    	}
    	public void setMaxPoolSize(int maxPoolSize) {
    		this.maxPoolSize = maxPoolSize;
    	}
    	public int getMaxLifetime() {
    		return maxLifetime;
    	}
    	public void setMaxLifetime(int maxLifetime) {
    		this.maxLifetime = maxLifetime;
    	}
    	public int getBorrowConnectionTimeout() {
    		return borrowConnectionTimeout;
    	}
    	public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
    		this.borrowConnectionTimeout = borrowConnectionTimeout;
    	}
    	public int getLoginTimeout() {
    		return loginTimeout;
    	}
    	public void setLoginTimeout(int loginTimeout) {
    		this.loginTimeout = loginTimeout;
    	}
    	public int getMaintenanceInterval() {
    		return maintenanceInterval;
    	}
    	public void setMaintenanceInterval(int maintenanceInterval) {
    		this.maintenanceInterval = maintenanceInterval;
    	}
    	public int getMaxIdleTime() {
    		return maxIdleTime;
    	}
    	public void setMaxIdleTime(int maxIdleTime) {
    		this.maxIdleTime = maxIdleTime;
    	}
    	public String getTestQuery() {
    		return testQuery;
    	}
    	public void setTestQuery(String testQuery) {
    		this.testQuery = testQuery;
    	}
    	
    }
    
    
    

    DBConfig2.java

     

     

    package com.itmayiedu.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    								
    @ConfigurationProperties(prefix = "mysql.datasource.test2")
    public class DBConfig2 {
    
    	private String url;
    	private String username;
    	private String password;
    	private int minPoolSize;
    	private int maxPoolSize;
    	private int maxLifetime;
    	private int borrowConnectionTimeout;
    	private int loginTimeout;
    	private int maintenanceInterval;
    	private int maxIdleTime;
    	private String testQuery;
    	public String getUrl() {
    		return url;
    	}
    	public void setUrl(String url) {
    		this.url = url;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public int getMinPoolSize() {
    		return minPoolSize;
    	}
    	public void setMinPoolSize(int minPoolSize) {
    		this.minPoolSize = minPoolSize;
    	}
    	public int getMaxPoolSize() {
    		return maxPoolSize;
    	}
    	public void setMaxPoolSize(int maxPoolSize) {
    		this.maxPoolSize = maxPoolSize;
    	}
    	public int getMaxLifetime() {
    		return maxLifetime;
    	}
    	public void setMaxLifetime(int maxLifetime) {
    		this.maxLifetime = maxLifetime;
    	}
    	public int getBorrowConnectionTimeout() {
    		return borrowConnectionTimeout;
    	}
    	public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
    		this.borrowConnectionTimeout = borrowConnectionTimeout;
    	}
    	public int getLoginTimeout() {
    		return loginTimeout;
    	}
    	public void setLoginTimeout(int loginTimeout) {
    		this.loginTimeout = loginTimeout;
    	}
    	public int getMaintenanceInterval() {
    		return maintenanceInterval;
    	}
    	public void setMaintenanceInterval(int maintenanceInterval) {
    		this.maintenanceInterval = maintenanceInterval;
    	}
    	public int getMaxIdleTime() {
    		return maxIdleTime;
    	}
    	public void setMaxIdleTime(int maxIdleTime) {
    		this.maxIdleTime = maxIdleTime;
    	}
    	public String getTestQuery() {
    		return testQuery;
    	}
    	public void setTestQuery(String testQuery) {
    		this.testQuery = testQuery;
    	}
    	
    }

     


    4,配置TestMyBatisConfig1,TestMyBatisConfig2,将两个数据源放入atomikos进行一个管理

     

     

    TestMyBatisConfig1

    package com.itmayiedu.datasource;
    
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    
    import com.itmayiedu.config.DBConfig1;
    import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
    
    @Configuration
    @MapperScan(basePackages = "com.itmayiedu.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
    public class TestMyBatisConfig1 {
    
    	// 配置数据源
    	@Primary
    	@Bean(name = "testDataSource")
    	public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
    		MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
    		mysqlXaDataSource.setUrl(testConfig.getUrl());
    		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    		mysqlXaDataSource.setPassword(testConfig.getPassword());
    		mysqlXaDataSource.setUser(testConfig.getUsername());
    		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    
    		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
    		xaDataSource.setXaDataSource(mysqlXaDataSource);
    		xaDataSource.setUniqueResourceName("testDataSource");
    
    		xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
    		xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
    		xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
    		xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
    		xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
    		xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
    		xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
    		xaDataSource.setTestQuery(testConfig.getTestQuery());
    		return xaDataSource;
    	}
    	@Primary
    	@Bean(name = "testSqlSessionFactory")
    	public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
    			throws Exception {
    		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    		bean.setDataSource(dataSource);
    		return bean.getObject();
    	}
    	
    	@Primary
    	@Bean(name = "testSqlSessionTemplate")
    	public SqlSessionTemplate testSqlSessionTemplate(
    			@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    		return new SqlSessionTemplate(sqlSessionFactory);
    	}
    }
    


    TestMyBatisConfig2

     

     

    package com.itmayiedu.datasource;
    
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.itmayiedu.config.DBConfig1;
    import com.itmayiedu.config.DBConfig2;
    import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
    
    @Configuration
    //basePackages 最好分开配置 如果放在同一个文件夹可能会报错
    @MapperScan(basePackages = "com.itmayiedu.test02", sqlSessionTemplateRef = "testSqlSessionTemplate2")
    public class TestMyBatisConfig2 {
    
    	// 配置数据源
    	@Bean(name = "testDataSource2")
    	public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
    		MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
    		mysqlXaDataSource.setUrl(testConfig.getUrl());
    		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    		mysqlXaDataSource.setPassword(testConfig.getPassword());
    		mysqlXaDataSource.setUser(testConfig.getUsername());
    		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    
    		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
    		xaDataSource.setXaDataSource(mysqlXaDataSource);
    		xaDataSource.setUniqueResourceName("testDataSource2");
    
    		xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
    		xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
    		xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
    		xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
    		xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
    		xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
    		xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
    		xaDataSource.setTestQuery(testConfig.getTestQuery());
    		return xaDataSource;
    	}
    
    	@Bean(name = "testSqlSessionFactory2")
    	public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource2") DataSource dataSource)
    			throws Exception {
    		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    		bean.setDataSource(dataSource);
    		return bean.getObject();
    	}
    
    	@Bean(name = "testSqlSessionTemplate2")
    	public SqlSessionTemplate testSqlSessionTemplate(
    			@Qualifier("testSqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
    		return new SqlSessionTemplate(sqlSessionFactory);
    	}
    }
    


    外加附上service层代码

     

     

    package com.itmayiedu.test01.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.itmayiedu.entity.UserEntity;
    import com.itmayiedu.test01.mapping.UserMapper1;
    import com.itmayiedu.test02.mapping.UserMapper2;
    
    @Service
    public class UserService1 {
    	@Autowired
    	private UserMapper1 userMapper1;
    	
    	@Autowired
    	private UserMapper2 userMapper2;
    	
    	@Transactional
    	 public int addUser1 (UserEntity userEntity){
    		 userMapper2.addUser(userEntity.getName(), userEntity.getAge());
    		 userMapper1.addUser(userEntity.getName(), userEntity.getAge());
    		 return 1;
    	 }
    }
    

    其他的地方不需改动,到此已经结束。希望可以帮助到各位同学,写得有错误的地方,希望各位同学可以指证出来。谢谢!

     

     

    展开全文
  • Spring多数据源分布式事务管理

    热门讨论 2016-04-19 15:10:56
    Spring多数据源分布式事务管理/springmvc+spring+atomikos[jta]+druid+mybatis
  • 分布式数据库 第六章 分布式事务管理 东北大学 分布式数据库系统
  • 最近笔者在面试过程中发现,分布式的微服务开发越来越广泛了,越来越多的企业在面试时都需要有微服务的经验,那么在谈到微服务的过程中,很多的面试官都会问到一个问题:有没有接触过分布式事务管理?怎么实现分布式...

        最近笔者在面试过程中发现,分布式的微服务开发越来越广泛了,越来越多的企业在面试时都需要有微服务的经验,那么在谈到微服务的过程中,很多的面试官都会问到一个问题:有没有接触过分布式事务管理?怎么实现分布式事务管理?

     

        那在这里就先要理解一下,什么是分布式事务管理,在单系统中,事务管理想必大家都很清楚,举个栗子,银行转账的过程中,张三的余额有100元,李四0元,张三要转50元给李四,那么数据库就要保证张三的记录和李四的记录同时修改,要么同时修改,要么不改,那么事务管理就是为了解决这种情况而存在的;单系统中,这种办法很好解决!加个注解就完事了!

        现在大多数项目都用的微服务;多个模块之间相互调用频繁,使得我们也要考虑到分布式事务的问题,比如以下这种情况,用户下单后,扣库存失败,那么会导致超卖,如果下单不成功,扣库存成功,会导致少卖,这两种情况都会导致运营成本增加,在严重情况下需要赔偿用户损失;

    那么怎么解决这个问题呢?

        目前有2种方案,TCC 和 LCN;

        TCC解决方案

    第一个T:trying,先冻结需要修改的数据,比如库存100卖掉2个,先把卖掉的2冻结起来,库存剩余98;

    第二个T:confirm,如果trying操作成功了,就进行确认操作,将冻结的 2 清零,这下库存就真的是98个了;

    第三个C:cancel,取消(回滚),如果trying 失败或者异常,进行回滚操作,将冻结的数量 2 加回库存,使库存回滚回原来的数量 2+98=100;

    具体执行内容如下图:

     

         LCN解决方案

     注意:LCN不生产任何事务,LCN只是本地事物的协调工具,负责管理微服务的事务;

    1、创建事务组

    2、各个微服务加入事务组

    3、所有的服务执行完sql语句后先不提交,而是通知事务管理器;

    4、事务管理器收到各个服务操作成功并且没有失败时,会发送消息通知相应的服务执行提交操作;但只要有一个服务在执行过程中出现异常,事务管理器会发生消息通知相应服务进行回滚操作!

    管理流程如下:

    是是

     

    有一些网站上说的非常详细,虽然详细但是看的人眼花缭乱,反而不好理解,我的这种方式更好的诠释了分布式事务的执行过程,和解决方案!当然,既然是通俗版的,肯定不会讲的那么详细,但是拿去面试还是可以将就用的!

    展开全文
  • 请解释分布式事务管理? 解答:分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。为了实现分布式事务,需要使用下面将介绍的两阶段提交协议。 ...
  • 二、传统的分布式事务管理解决方案 1.两阶段提交方案/XA方案 2.TCC方案 三、seata解决方案 四、Seata有3个基本组件 五、Seata管理的分布式事务的典型生命周期 六、快速开始 一、seata是什么 Seata 一个简单...
  • Spring Cloud 分布式事务管理

    千次阅读 2018-08-07 11:30:36
    Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率.   Spring Cloud 分布式事务管理 ...
  • tcc-transaction分布式事务管理器。底层纯java+spring切面实现,tcc-transaction  不和底层使用的rpc框架耦合,也就是使用dubbo,thrift,web service,http等都可。
  • spring+hibernate+atomikos实现多数据源分布式事务管理
  • Spring+Hibernate+Atomikos多数据源分布式事务管理,性能低,耗时性长,请问有什么方法可以解决这个问题,求指教
  • 事务管理之XA分布式事务管理

    千次阅读 2017-08-05 14:39:51
    Java Transaction API 允许您操作应用程序中的分布式事务...在异构环境中,您通常会发现一个事务管理器(Transaction Manager),负责处理分布式事务。(实际上,事务管理器可以完成大量的工作负载平衡。)因
  • springmvcmybatis多数据源分布式事务管理 pom依赖 jtaproperties 配置数据源 配置SQLSessionFactory 配置MapperScanner 配置Jta事务 实体 dao XML service Junit测试 完结springmvc+mybatis多数据源分布式事务管理 ...
  • 通过上一篇的介绍,我们知道了SOA真正需要的是一个能够协调服务操作直接(通过服务自身访问的资源)或者间接(通过被调用服务访问的资源)访问的所有资源的分布式事务管理系统,这是一个复杂的架构体系。WCF,作为...
  • Spring Cloud 分布式事务管理(二)2pc/3pc
  • 摘要:云原生2.0时代,微服务架构下如何保证数据的一致性是非常重要的一个课题。4月8日,在华为云TechWave全球技术峰会分布式云分论坛上,华为云技术专家深度解读华为云分布式事务管理DTM。
  • springboot分布式事务管理: 在多数据源的情况下,进行事务管理的方法: jta+atomikos两段提交协议 MQ推送-
  • 一个事务设计两个数据源操作,需要使用atomikos来构建分布式事务管理器, 官网:https://www.atomikos.com/Main/AtomikosResources 简单记录几个还算靠谱的博客 ... ...
  • txlcn-分布式事务管理入门

    千次阅读 2019-10-23 08:43:45
    公司突然有分布式事务的需求,抽空研究一下相关的框架,发现txlcn相对比较成熟。 官方入门文档:https://www.txlcn.org/zh-cn/docs/start.html 这里记录一下接入遇到的坑。 TX-LCN 主要有两个模块,Tx-Client(TC) Tx...
  • https://www.jianshu.com/p/e16cf4e325e2 https://blog.csdn.net/he90227/article/details/52493580 涉及3个数据源以上的多数据源配置和分布式事务管理
  • lcn 分布式事务管理

    2019-05-08 17:16:30
    lcn 分布式事务https://github.com/codingapi/springcloud-lcn-demo/tree/master/jpa-demo/springcloud-jpa-demo1 lcn 分布式事务文档:https://txlcn.org/zh-cn/docs/start.html
  • Spring Cloud 分布式事务管理(二)2pc/3pc 上一篇 Spring Cloud 分布式事务管理 上一章,讲到了微服务带来的优点和缺点以及分布式事务的不确定性。这节说一下2pc/3pc 的具体解决方案 在分布式系统,我们会...
  • spring多数据源的配置(分布式事务管理
  • 用SpringJTA进行分布式事务管理,需要引入第三方UserTransaction。例如:JOTM、Atomikos JOTM (Java Open Transaction Manager)是一个独立的开源事务管理器,它实现了 XA 协议并且与 JTA API 兼容。 Atomikos...
  • Springboot入门之分布式事务管理

    千次阅读 2017-12-21 22:41:20
    springboot默认集成事务,只主要在方法...分布式事务一种情况是针对多数据源,解决方案这里使用springboot+jta+atomikos来解决。 一、pom文件 cn.iponkan springboot-jsp 1.0-SNAPSHOT org.springframework.boot
  • LCN分布式事务管理  官方地址: http://www.txlcn.org/     下载工具 首先,你可以参考官网,官网有更详细的讲解:https://github.com/codingapi/tx-lcn 如果想使用整理好的包,可以从这下载, 按照配置说明...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 167,121
精华内容 66,848
关键字:

分布式事务管理