天天看点

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

<a href="http://my.oschina.net/pingpangkuangmo/blog/413518">分布式事务系列(开篇)提出疑问和研究过程</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/415162">分布式事务系列(1.1)spring事务管理器platformtransactionmanager源码分析</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/416038">分布式事务系列(1.2)spring事务体系</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/417479">分布式事务系列(2.1)分布式事务模型与接口定义</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/419374">分布式事务系列(3.1)jotm的分布式案例</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/420831">分布式事务系列(3.2)jotm分布式事务源码分析</a>

<a href="http://my.oschina.net/pingpangkuangmo/blog/423210">分布式事务系列(4.1)atomikos的分布式案例</a>

先来感受下一个分布式事务的案例(使用一般的数据库驱动,不需要支持分布式xa协议):

userdao和logdao,操作分别如下:

即上述两个jdbctemplate使用不同的数据库。

userservice综合上述两个业务操作,使它们处于同一个事务中:

上述业务代码我们看不到分布式事务的存在,这种正是我们想要的效果,分布式事务对业务透明。到底是如何来实现呢?

自行配置2个数据库地址

我们平常使用的datasource,大部分是c3p0、dbcp等,这里就不能使用它们了,需要换成可以模拟xa协议的datasource,即standardxapooldatasource。这个连接池是xapool提供的。

它设计了一个genericpool,这个pool里面可以存放任何object

它提供了datasource的实现,同时还提供了针对分布式的datasource即standardxapooldatasource,它可以通过使用普通的数据库驱动来模拟两阶段提交协议中xaresource的作用。本来xaresource是需要由数据库xa驱动来实现的。

不过好久都没更新了,官网上最近一次更新还是06年

之后再详细介绍它的源码内容。

我们知道分布式事务中需要一个事务管理器即接口javax.transaction.transactionmanager、面向开发人员的javax.transaction.usertransaction。对于jotm来说,他们的实现类都是current,如下源码所示:

我们如果想使用分布式事务的同时,又想使用spring带给我们的@transactional便利,就需要配置一个jtatransactionmanager,而该jtatransactionmanager是需要一个usertransaction实例的,所以用到了上面的current,如下配置:

同时上述standardxadatasource是需要一个transactionmanager实例的,所以上述standardxadatasource配置把jotm加了进去

整个工程主要是利用jotm和xapool来实现分布式事务。jotm提供事务管理器javax.transaction.transactionmanager和面向开发人员的功能接口javax.transaction.usertransaction,而xapool则是对非xa数据库驱动进行包装,来模拟xa数据库驱动干的事。所以依赖的pom如下:

上述jotm-datasource主要是为了将上述standardxapooldatasource数据源放置到容器中,如tomcat,而不是应用程序中。应用程序通过jndi的方式从tomcat容器中获取上述数据源。所以对于本工程来说可以不要,对于下文说的通过jndi方式使用jotm则是必须的

下面先粗略的说明下分布式事务的大致执行过程,即下面的执行过程:

第一步:事务拦截器开启事务

我们知道加入了@transactional注解,同时开启tx:annotation-driven,会对本对象进行代理,加入事务拦截器。在事务拦截器中,获取javax.transaction.usertransaction,这里即org.objectweb.jotm.current,然后使用它开启事务,并和当前线程进行绑定,绑定关系数据存放在org.objectweb.jotm.current中

第二步:使用jdbctemplate进行业务操作

jdbctemplatea要从datasourcea中获取connection,和当前线程进行绑定,同时以对应的datasourcea作为key。同时判断当前线程是否含有事务,通过datasourcea中的org.objectweb.jotm.current发现当前线程有事务,则把connection自动提交设置为false,同时将该连接纳入当前事务中。

jdbctemplateb要从datasourceb中获取connection,和当前线程进行绑定,同时以对应的datasourceb作为key。同时判断当前线程是否含有事务,通过datasourceb中的org.objectweb.jotm.current发现当前线程有事务,则把connection自动提交设置为false,同时将该连接纳入当前事务中。

第三步:

一旦抛出异常,则需要进行事务的回滚操作。回滚就是将当前事务进行回滚,该事务的回滚会调用和它关联的所有connection的回滚。

这里再举一个简单的例子,如下:

我们这样做:把所有的connection的自动提交都设置为false,一旦执行过程中发生异常,调用每个connection的回滚方法,如果没异常,则全部提交。这样做也可以实现分布式事务操作。

jotm也是同样的思路,在上述工程中,使用jdbctemplate操作,就会把使用的connection的自动提交设置为false,同时把这个connection交给事务管理,一旦抛出异常,事务就会把它拥有的所有connection全部回滚。

再介绍下通过jndi方式如何来使用jotm,以及碰到的最新版jotm-core中的一个bug。

第一步:先通过jndi方式获取面向开发人员的usertransaction事务

第二步:通过jndi方式获取datasource,然后进行sql操作

第三步:使用usertransaction提交事务

第四步:一旦执行过程中发生异常,使用usertransaction回滚事务

在tomcat的context.xml配置文件中如下方式配置:

配置如下:

这个配置默认将"java:comp/usertransaction"和上述usertransactionfactory产生的对象关联了起来(还不太了解jndi的话,需要去补充下知识)。所以可以通过如下方式来获取:

我们来看下,jotm提供的usertransaction实现是什么对象,即该usertransactionfactory产生的对象是?

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

可以看到提供的usertransaction实现是org.objectweb.jotm.current。

我们来仔细研究下,它到底用的是什么datasource,来看下上述配置的factory即org.objectweb.jotm.datasource.datasourcefactory的内容:

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

可以看到这里和spring中的配置文件里基本差不多,多和上面的spring配置文件对比对比。

创建standardxadatasource,设置相关参数

创建standardxapooldatasource,设置相关参数

继续,下面还有:

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

将standardxadatasource设置进standardxapooldatasource中。 同时standardxapooldatasource需要设置下事务管理器transactionmanager,通过jotm对象来获取的。

上述事务管理器是从jotm对象获取的,我们继续看下jotm是如何来的?这里正是jotm-core-2.3.1-m1.jar出现bug的地方:

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

即在加载datasourcefactory类的时候,就会创建jotm,来详细看下2.3.1-m1版本的创建方法:

可以看到,这里的第三个参数为null,继续看下第三个参数是干什么的?

分布式事务系列(3.1)jotm的分布式案例1 系列目录2 与Spring集成方式使用jotm3 通过JNDI方式使用jotm4 结束语

我们可以看到第三个参数为null,会产生运行时异常即空指针异常,没有捕获到继续向上层传递,而datasourcefactory也没有捕获到,直接导致datasourcefactory类加载失败。

解决办法就是换成低版本的jotm-core,如2.2.2版本就可以了,不会产生上述问题。或者直接调用三个参数的构造函数,对于第三个参数给出一个空的实现

本篇主要说明了与spring集成方式的jotm案例、使用jndi方式的jotm案例。下一篇就该详细介绍下整个过程的执行原理。提出的问题如下:

jotm做了哪方面的工作?

xapool做了哪方面的工作?

2pc的过程怎么体现的?