Spring Dao编程高级-Spring中的分布式事务控制

从 0 开始深入学习 Spring 专栏目录总览

分布式事务控制,听起来貌似离我们很遥远,但如果小伙伴是因为加强和巩固 SpringFramework 的知识的话,想必你可能接触过分布式应用的开发吧,分布式的场景下,难免会遇到分布式事务的麻烦。学过分布式事务的小伙伴可能知道有什么 2PC 、TCC 、可靠消息等等的方案,那在 SpringFramework 中,其实它有设计一种 JTA 的分布式事务解决方案。这一章咱简单来简单了解一下,注意,也仅仅是了解。

1. 事务与分布式事务【了解】

首先,咱先快速认识一下分布式事务。

1.1 认识分布式事务

事务的概念咱都不陌生了,咱之前学习的所有关于事务的概念,都是指的基于关系型数据库的本地事务。那分布式事务就是相对于本地事务而言的概念了,分布式事务,指的是由不同的应用 / 关系型数据库之间,通过网络远程协作完成的事务

对于同一个业务动作,如创建订单扣库存,则以下三种架构都属于分布式事务的范畴:

  1. 多个应用同时访问一个数据库,应用间共同完成事务操作
  2. 多个应用访问不同的数据库,应用间共同完成事务操作
  3. 一个应用同时访问多个数据库,由应用内控制完成事务操作

Spring Dao编程高级-Spring中的分布式事务控制

SpringFramework 的分布式事务,实现的是类似于第三种的分布式事务。

1.2 SpringFramework的分布式事务

之前我们在学习 SpringFramework 事务控制模型的事务管理器时,留下了一个悬念,是 JTATransactionManager ,它就是用来实现分布式事务控制的。其实更恰当的说,这个 JTA 事务叫它全局事务更为合适。

如上面的图 3 所示,商城应用要处理创建订单扣库存的业务逻辑,而订单数据库和库存数据库在两个不同的关系型数据库中,咱知道基于数据源的事务管理器 DataSourceTransactionManager 是一个数据源对应一个事务管理器,事务管理器之间无法互相干预。所以,SpringFramework 提供了 JTA 全局事务,来同时控制多个数据源的事务。

继续往下之前,小册在这里先提前介绍几个概念,小伙伴们要先理解它们,理解之后,再学习分布式事务的内容会更加容易。

  • 全局事务管理器:控制一整个分布式事务的事务管理器,它可以控制一个分布式事务中各个节点分支上的事务提交或回滚
  • 资源管理器:可以简单的理解为关系型数据库
  • 应用程序:我们自己编写的程序

1.3 2PC解决分布式事务

还是以上面的 “创建订单扣库存” 场景为例,当一个应用同时连接订单、库存两个数据库时,需要同时控制这两个数据库的事务同时成功或者失败。针对这种情况,可以使用 2PC 方式来解决。2PC 即两阶段提交协议,它将一个事务的提交动作拆解为两个阶段:准备阶段( prepare )和提交阶段( commit )。

准备阶段下,全局事务管理器会给每个分支事务对应的资源管理器,发送一个 prepare 的消息,告诉资源管理器要准备提交事务了,此时每个分支事务均在本地执行,但都没有提交。当每个资源管理器的 prepare 动作均执行成功后,全局事务管理器会收到这些成功的消息,并且发送 commit 消息示意所有分支事务提交;如果有任何资源管理器的 prepare 动作失败或者连接超时,全局事务管理器也会感知到失败的消息,并发送 rollback 消息,通知所有资源管理器回滚事务。如此一套流程下来,就完成了一次分布式事务的两阶段提交。

Spring Dao编程高级-Spring中的分布式事务控制

1.4 XA与JTA事务

之所以前面先提到 2PC 协议,是为了引出接下来咱要说的落地方案。2PC 方案在传统的落地方案中有一种 XA 方案,它是依赖于传统的关系型数据库实现的,MySQL 、Oracle 等数据库都支持基于 XA 方案的 2PC 协议。XA 方案是由一个国际开放标准组织定义的分布式事务处理模型 DTP ,它的处理逻辑就是依照上面描述的 2PC 逻辑而来。

  1. 使用 XA 方案之前,应用程序会同时持有多个数据源
  2. 当触发分布式事务时,应用程序会通过全局事务管理器,通知资源管理器执行本地事务,但不提交,此时每个资源管理器中的数据都会被锁定
  3. 若全局事务管理器发出的 prepare 消息全部收回成功,则通知所有资源管理器提交事务,释放资源
  4. 若全局事务管理器收到任何一个失败的消息,则通知所有资源管理器回滚事务,释放资源

注意,在这里,XA 指代的是全局事务管理器与资源管理器之间的交互接口规范,它并不是整个方案的代名词,只是说,基于这个 XA 交互接口规范的 2PC 解决方案被称为 XA 方案而已。

那 JTA 又是啥呢?JTA 其实就是 XA 方案的 java 实现。JTA 全程 Java Transaction Api ,API 那就是规范,所以 JTA 也仅仅是定义了一些接口而已,实际干活的还得是落地的实现。

使用 JTA ,目前来看有两种可实现的方式:借助外部 Web 容器,或者借助第三方 JTA 库。对于前者,需要外部的 Web 容器具备 JTA 事务的支持,目前还能支持的有 JBOSS 等;后者的话,在目前来看,比较流行的框架有 Atomaikos 、JOTM 等,它们的使用小伙伴们可以自行学习,小册不在此展开详细介绍了(一展开就爆炸多)。

2. Spring与JTA【了解】

前面说了那么多,SpringFramework 中的 JTA 又是怎样的呢?

2.1 JNDI

不是,SpringFramework 的东西还没搞,又来了个 JNDI ?这是搁这知识科普吗?

我想可能很多小伙伴都产生很大的疑惑了,咋全是科普概念了?莫慌,SpringFramework 的 JTA 要与 JNDI 配合使用,所以咱要先了解 JNDI 。

JNDI 全程叫 Java Naming and Directory Interface ,Java命名和目录接口,它是一种标准的 Java 命名系统接口。说的那么抽象,其实用一个东西类比就好多了:Windows 的注册表。Windows 中的注册表存放了很多 Windows 操作系统、软件的配置等,JNDI 也是如此。

举个简单的栗子,在我的 PC 上,找到注册表编辑器,可以在 HKEY_CURRENT_USER\Software\7-Zip 下找到一个 7zip 的安装路径配置:

Spring Dao编程高级-Spring中的分布式事务控制

另外,在 HKEY_LOCAL_MACHINE\SOFTWARE\7-Zip 下也能找到一个一样的 7zip 的 Path 定义。很明显这两个配置虽然数据一致,但路径不一致。这就很像咱写的那些 Java 类,类名可以一致,但全限定名不能一致就好。

那么这样看来,两个配置就可以分别写作:HKEY_CURRENT_USER\Software\7-Zip\Path=...... 、HKEY_LOCAL_MACHINE\SOFTWARE\7-Zip\Path=...... 。

有种什么感觉?说白了,这不就是个 properties 吗?哎还真就这么回事,所以使用 JNDI 的本质上也可以理解为配置一堆 properties 。只不过这里面非常大的一个区别是,JNDI 中 properties 的值可以是任意 Object 。

那话说回来,JNDI 可以干嘛呢?一个实际的使用方式,是在一个 Web 容器(如 Tomcat )中,给整个 Web 容器注册一个公共的 DataSource ,这个 DataSource 可以供 Web 容器的所有工程使用,就像这样:

Spring Dao编程高级-Spring中的分布式事务控制

上面的这个图中,order-service 工程和 store-service 工程都可以拿到 Tomcat 中的这个 DataSource 。

更多有关 JNDI 的内容,小伙伴可以自行搜索学习相关知识,小册不在此过多展开讲解。

2.2 Spring使用JTA的两种方式

之所以上面引入 JNDI ,是因为接下来的内容马上就会用到。对于一个基于 SpringFramework 的应用来讲,使用 JTA 事务可以有两种方案。但无论使用哪种,必备的角色一样也不能少,它们分别有:

  • 全局事务管理器
  • JTA 资源管理器
  • 资源服务器(关系型数据库等)

而在 SpringFramework 中,能提供的只有事务管理器,以及资源服务器( DataSource ),至于 JTA 资源管理器,前面咱也说到了,要么 Web 容器提供,要么第三方框架提供。下面咱分别介绍一下这两种实现方式的架构原理。

2.2.1 外部Web容器提供

如果 JTA 资源管理器由 Web 容器提供,整体的分布式事务架构图就应该是这样的:

Spring Dao编程高级-Spring中的分布式事务控制

在这种方案下,当外部资源调用触发事务时,由 SpringFramework 的事务管理接收,并由 JTATransactionManager 接管落地实现,由于此时的 JTA 资源管理器是外部的 Web 容器提供,所以此处会调用到外部的 JTA 资源管理器(这个调用很像委派的机制),并由外部的 JTA 资源管理器负责控制具体的资源(数据源)完成与数据库的交互。

2.2.2 第三方框架提供

如果使用第三方框架提供 JTA 资源管理器,则架构会变为如下形式:

Spring Dao编程高级-Spring中的分布式事务控制

可见这种方案下,Atomikos 是作为 SpringFramework 的 IOC 容器中的一部分,SpringFramework 的 JTATransactionManager 在调用具体的 JTA 资源管理器时,是直接从 IOC 容器中找对应的 bean 即可,整体事务控制的思路不变。

OK 有关 Spring 中的分布式事务控制就简单介绍这么多吧,这部分虽然是 SpringFramework 的一部分,但实际使用已然少之又少,因为基于 XA 规范的 2PC 协议,吞吐量太差,性能不高,所以早就被更优的方案取缔了。

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » Spring Dao编程高级-Spring中的分布式事务控制