067-分布式事务

作者: 郭艺宾 | 来源:发表于2018-11-21 17:23 被阅读1次

    什么是分布式事务

    分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

    只看定义略显抽象,我们从简单的单机事务开始,事务就是作为单个逻辑单元执行的一组操作,要么全成功,要么全失败,事务共包含四个特性:原子性,一致性,隔离性,持久性。单机事务做过数据库的基本都知道,理解简单,使用也简单。

    再来看一个分布式系统,我们购物时往往会同时操作订单系统和库存系统,同时操作两个系统,可能就会出现一个成功,一个失败的情况,比如订单下了,库存却没扣,这个时候出现的就是数据不一致的情况。这种时候必须要保证数据一致性,单数据源的一致性依靠单机事务来保证,多数据源的一致性就要依靠分布式事务

    Atomikos TransactionsEssentials

    Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器,以下是包括在这个开源版本中的一些功能:

    全面崩溃 / 重启恢复

    兼容标准的SUN公司JTA API

    嵌套事务

    为XA和非XA提供内置的JDBC适配器

    XA:XA协议由Tuxedo首先提出的,并交给X/Open组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,Oracle、Informix、DB2和Sybase等各大数据库厂家都提供对XA的支持。XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。XA协议包括两套函数,以xa_开头的及以ax_开头的。

    以下的函数使事务管理器可以对资源管理器进行的操作:

    1)xa_open,xa_close:建立和关闭与资源管理器的连接。

    2)xa_start,xa_end:开始和结束一个本地事务。

    3)xa_prepare,xa_commit,xa_rollback:预提交、提交和回滚一个本地事务。

    4)xa_recover:回滚一个已进行预提交的事务。

    5)ax_开头的函数使资源管理器可以动态地在事务管理器中进行注册,并可以对XID(TRANSACTION IDS)进行操作。

    6)ax_reg,ax_unreg;允许一个资源管理器在一个TMS(TRANSACTION MANAGER SERVER)中动态注册或撤消注册。

    内置的JMS适配器XA-capable JMS队列连接器,通过XA API兼容第三方适配器,更好的整合您的项目,集成Hibernate。

    JMS:jms即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。

    Atomikos TransactionsEssentials 是一个可靠的库,可以加入到您的Java应用程序,也就是说为了使用这个产品,您必须添加一些jar文件(包括在dist和lib文件夹下)到您的应用程序或者应用程序服务器。

    请注意:Atomikos TransactionsEssentials是一个非常快速的嵌入式事务管理器,这就意味着,您不需要另外启动一个单独的事务管理器进程(不要查找任何的bin文件夹)。相反,您的应用服务器将有它自己的intra-VM事务管理器。

    尽管这个软件有着很大的优势,但是想要更好的发挥其作用,可以按以下的方法优化:

    更高的内存,意味着更高的吞吐量(每秒的事务数目)

    使连接池尽可能的大

    一旦你不需要的连接请马上关闭它们。不要把你的应用程序放在缓存里,让内部连接池为你做这些,这将促使更高效的连接使用

    不要让活动的事务闲置:终止所有情况下的事务,尤其是在异常报错情况下的事务。这将减少数据库的锁定时间,并且最大效率的处理启用的使用。

    下面开始使用springboot整合Atomikos,首先建立一个多数据源的项目,先看pom:

    可以看到,用最简单的形式,只添加了web和数据组件,因为我们要自定义多个数据源,所以我把springboot启动时默认配置的数据源取消:

    然后在配置文件中配置多个数据源:

    接下来写两个配置配开始配置数据源:

    第二个:

    注意,其中一个要加上@Primary注解,如果不加这个注解,启动将会报错,因为服务器先要有一个默认不知道默认要先访问的数据源是哪个,必须指明。下面创建两个数据库:

    每个表的表结构和数据如下:

    接下来创建两个实体类:

    然后创建两个mapper类,每个类中包含一个查询和一个新增方法:

    最后看service和controller:

    编码工作完成了,下面启动项目,测试这两个接口:

    可以看到两个数据源分开访问,是没有问题的。那么一起操作呢?增加一个service和接口:

    清空数据库,然后访问接口:

    可以看到正常情况下也能操作成功。我们的insert方法并没有加事务,是因为两个数据源分别有各自不同的事务管理器,如果加上@Transactional注解会报错。如果我们让中间发生一次异常:

    清空数据库,重启,然后访问:

    可以看到报错,数据库中也是成功了一个失败了一个。这是常见的分布式事务问题,下面我们整合Atomikos,首先添加依赖:

    启动类不用调整,修改一下配置文件:

    然后接下来修改两个数据源配置类:

    然后在新增方法上加上事务注解:

    清空数据库,重启,访问接口:

    再次查询数据库,发现两个都没有成功,这正是我们想要的效果。

    Bitronix transaction manager

    wait

    Narayana transaction manager

    wait

    Java EE managed transaction manager

    wait

    JBossTransaction

    wait

    代码地址:https://gitee.com/blueses/spring-boot-demo

    相关文章

      网友评论

        本文标题:067-分布式事务

        本文链接:https://www.haomeiwen.com/subject/rtgcqqtx.html