Java事务学习一
最近工作中遇到了这样一个问题,使得我不得不开启自己计划已久的事务学习计划了。
问题是这个样子的:
如上图所示,我们从external queue中读取message,然后交给internal queue,再由internal queue更新到数据库。
其中,external queue采用的是IBM MQ,而internal queue则是Tomcat内部的JMS queue。由于二者不在同一台服务器上并且是不同类型的data source,需要一个XA transaction Manager来进行全局的分布式事务管理;同理,internal queue和数据库之间也需要用XA transaction Manager。
问题出现了。什么问题呢?
第一、事务管理的问题。当消息从internal queue更新到数据库时,杂乱在更新成功的情况下,internal queue中的消息并没有被移除;这导致了会有重复的message内容被更新到数据库。
第二、JDBC connection pool的问题。当前采用的connection pool不提供以下特性:验证该connection pool中的connection是否有效,如果无效,则移除。由此引起的问题是,当该connection pool中存在无效connection时,不会被移除,而是反复的被client从该connection pool中取出,从而导致应用出现问题。
哇啦啦,终于把问题交代完啦。
据说,某菲在看这个问题描述的时候,单单从问题描述中,就一条一条的揪出来十个需要学习的点(而且还木有发散)。
于是,我深深的认识到了学习事务的决定不能再拖下去了!于是,我又从杂乱的download文件夹中找出了那本《Java transaction design strategy》
于是…便有了下面的内容。
首先,补一下基本概念:
1. JDBC connection pool:
这个叫做JDBC connection pool的池子和所有的池子都差不多,就是存放了很多很多的JDBC connection。
和其他池子的管理规定也差不多,client可以从这个池子借走一根JDBC connection,然后用,用完了之后再还回来。
使用池子的好处和目的也差不多,就是在有多用户的情况下更加灵活有效地调到资源。
学术一点:
client会在JNDI Tree上查找data source,这个JNDI tree上的每个data source 都会从connection pool里面找connection,然后connection pool会让JDBC driver创建数据库的物理连接。
client分为internal client和external client,分别表示这个client在server的内部或者外部。
关于JDBC connection pool的小故事就先讲到这里。这里是最基本的基本知识,接下来我们就聊一下对于这个问题的解决方案,我们希望采用的Tomcat JDBC connection pool,当然他具备所有上述JDBC connection pool的基本特性,同时又有自身的独特优势。
2. Tomcat JDBC connection pool
上面提到我们决定采用Tomcat JDBC connection pool作为解决那个JDBC connection pool没有对无效connection做检测的问题。
这是因为Tomcat提供了这种特性:可以在从connection池子中借connection以及还connection之前,以及任何时候对connection是否有效健康进行检测,如果是不健康的,那么就会从这个connection池子中丢出去。
比如Tomcat JDBC connection pool提供了以下几个属性提供可配置的connection体检:
1) testOnBorrow:布尔值;用于配置connection池子是否会在借出去某个connection之前对其进行体检。如果体检不通过,池子就会把这个connection丢弃,并且试图借另一个connection出去。
那么池子君又是怎样对connection做体检的呢?
汤姆凯特家的池子还提供了这样一条属性:
1)validationQuery: String;池子就是通过运行这样一条SQL 语句来检查某根connection是否为正常的。通常会用“select 1”。
所以说嘛,我们可以用汤姆凯特家的JDBC connection pool去解决我们的问题。
3. XA
问题描述中反反复复的出现几个词:XA,XA-compliance,2-phase commit,1.5-phase commit。到底是什么意思呀?
首先XA,某师父说XA就是global或者global transaction,就是这么简单。那么全局事务是相对于局部事务的概念,分别对应于分布式系统的事务管理和单机事务管理。
举一个最简单的 分布式事务管理的例子,就是我们希望从一条queue中读出一个消息,然后更新到数据库中。
某师父还说,XA就等同于2-phase commit
XA-compliance就是说某个resource是遵循XA规范的。
扫噶!
那么什么是2-phase commit呢?这个也挺有意思的,就放在我的第四条吧:)
4. 2-phase commit(两阶段提交)
两阶段提交的 意思其实很好理解,就是把整个的事务提交过程分为两个阶段。
第一阶段称为等待提交与投票阶段:就是有一个中央调度员,等着他所管理的分布式事务系统中的各个同学完成他们的任务,等待他们传回自己各自的结果:或者提交,或者回滚。至此,第一阶段完成。
第二阶段称为统一提交阶段:中央调度员根据他收到的投票结果,做出最初决定,是否提交或者回滚,并且把该决策告知该分布式管理系统中的所有同学,然后这些同学们无论自己的执行结果是什么,都要服从中央的调度,该提交提交,该回滚回滚。
好啦,先写到这里吧,我要回家啦,哈哈!