Druid阅读(十)XA写入双数据库分析

目录

1 理清理论知识

2 执行写入双数据库源码分析

3 总结

4 彩蛋


1 理清理论知识

上篇文章已经分析到初始化AtomikosDataSourceBean后会最终初始化一个List<XPooledConnection> connections的连接池。具体分析可查看:Druid阅读(九)XA连接初始化_he_cha_bu的博客-CSDN博客

那么当执行两个数据库的写数据操作后的流程又是怎样的呢?

其实回答这个问题前需要先弄明白一个事情,那就是XA其实是对事务进行管理,Connection和stament是不变的,而XA的事务管理器的对象是 XAResource,所以在分析两个数据库的写数据操作的流程会发现XAResource进行了两阶段的操作,由于我们用的是Mysql数据库,所以这里对Mysql的XA接口进行简单的说明如下:

XA START xid: 开启一个事务,并将事务置于ACTIVE状态,此后执行的SQL语句都将置于该是事务中。
XA END xid: 将事务置于IDLE状态,表示事务内的SQL操作完成。
XA PREPARE xid: 实现事务提交的准备工作,事务状态置于PREPARED状态。事务如果无法完成提交前的准备操作,该语句会执行失败。
XA COMMIT xid: 事务最终提交,完成持久化。
XA ROLLBACK xid: 事务回滚终止。

弄明白这些知识点后接下来咱们去看下源码。

2 执行写入双数据库源码分析

查看MysqlXAConnection对象,发现实现了XAResource

public class MysqlXAConnection extends MysqlPooledConnection implements XAConnection, XAResource {}

然后查看其方法,发现里边有commit,end,prepare,start等。所以我们可以直接在这些方法debug,然后运行示例。

运行示例如下: 

已进入start方法,截图如下:

 查看调用栈信息如下,由atomikos管理调用:

 往下执行,就发现初始化的DruidPooledConnection开始工作,创建prepareStatement,这里基本可以知道Mysql调用start操作的时候就开始连接数据库执行操作,同样可从调用栈得知。

 两个数据源都start之后,就开始调用end方法如下:

 再下一步则是prepare方法,截图如下:

 最后没问题则执行commit提交,截图如下:

 最后查看数据库数据发现保存成功。同样用失败的案例做测试发现最后面会调用rollback方法回滚。

3 总结

整个过程会发现其实XA相当于是加了XAResource控制,而每一个XAResource又有事务管理器Atomikos控制,这样就达成分布式事务的效果。每次XAResource执行start()方法的时候就会获取连接,然后创建statment,最后执行操作。而这个过程跟我们之前分析的Druid的数据库操作过程是一样的。所以Druid在XA这一块所做的事情相当于是提供初始化的时候返回一个XAResource,然后自己还是只关心数据库连接,执行增删改查等非事务的事情。

4 彩蛋

再返回看XA初始化这块逻辑会发现atomikos会自行初始化一个连接池,源码如下:

 然后再查看返回的XAConnection是由Druid创建一个DruidPooledConnection和XAConnection的包装类DruidPooledXAConnection返回,源码如下:

 然后再看Druid的getConnection()方法会先初始化,然后返回一个连接。似乎没啥问题,那么问题来了,如果atomikos配置初始化20个连接,而Druid的最大连接只允许创建5个,那不就意味着atomikos连接池想从Druid这边获取20个连接不可行了吗?

 

 说着改成上述配置,试着debug观察了一下,发现Druid连接满后进入下面的代码段: 

 将抛出一个GetConnectionTimeoutException异常,代码如下:

 然后发现atomikos拿到异常后,直接处理返回连接为null

 

 然后会进行刷新refreshXAResource操作

 最终再查看会发现atomikos也只创建了五个连接。 


版权声明:本文为he_cha_bu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。