Spring+iBatis+Atomikos实现JTA事务
 
Atomikos是一个公司名字,旗下最著名的莫过于其Atomikos的事务管理器产品。
 
产品分两个:一个是开源的TransactionEssentials,一个是商业的ExtremeTransactions。
 
TransactionEssentials的主要特征:
JTA/XA 事务管理 —— 提供事务管理和连接池
不需要应用服务器 —— TransactionEssentials可以在任何Java EE应用服务器中运行,也就是不依赖于任何应用服务器
开源 —— TransactionEssentials是遵守Apache版本2许可的开源软件
专注于JDBC/JMS —— 支持所有XA资源,但是资源池和消息监听是专供JDBC和JMS的
与Spring 和 Hibernate 集成 —— 提供了描述如何与Spring和Hibernate集成的文档
 
ExtremeTransactions 是基于TransactionEssentials之上的,增加了对非XA事务的支持,在servlet容器中提供了图形化管理控制面板。Atomikos还提供了基于订阅的支持服务,一份订阅可以得到访问ExtremeTransactions中额外功能的权限。
Pardon继续说道,在很多情况下,一个应用服务器对于一个应用也许不是最佳方案 —— 他以SOA/ESB终端作为例子,阐述了通过JDBC来处理JMS消息可能是一个非常轻量级的可伸缩的方案。
 
 
关于TransactionEssentials的后继版本,Pardon提到了更强大的JDBC和JMS连接池,支持OSGi 和JMX事务管理工具,是计划中的3.3版的主要特征。Pardon还说明为JDBC数据源和JMS连接器增加JMX是4.0版的目标。
 
 
 
下面是Spring+iBatis+Atomikos实现JTA事务的测试过程:
 
一、环境
 
1、准备软件环境
 
 spring-framework-2.5.6.SEC01-with-dependencies.zip
 ibatis-2.3.4
 AtomikosTransactionsEssentials-3.5.5.zip
 MySQL-5.1
 JDK1.5
 
 
 
2、创建数据库环境,注意数据库引擎为InnoDB,只有这样才能支持事务。
 
CREATE 
DATABASE 
IF 
NOT 
EXISTS testdb_a        
DEFAULT CHARACTER 
SET utf8;    


USE testdb_a;    


DROP 
TABLE 
IF 
EXISTS tab_a;    


CREATE 
TABLE tab_a (    

        id 
bigint(20) 
NOT 
NULL,    

        
name 
varchar(60) 
DEFAULT 
NULL,    

        address 
varchar(120) 
DEFAULT 
NULL,    

        
PRIMARY 
KEY (id)    

) ENGINE=InnoDB 
DEFAULT CHARSET=utf8;    



CREATE 
DATABASE 
IF 
NOT 
EXISTS testdb_b        
DEFAULT CHARACTER 
SET utf8;    


USE testdb_b;    


DROP 
TABLE 
IF 
EXISTS tab_b;    


CREATE 
TABLE tab_b (    

        id 
bigint(20) 
NOT 
NULL,    

        
name 
varchar(60) 
DEFAULT 
NULL,    

        address 
varchar(120) 
DEFAULT 
NULL,    

        
PRIMARY 
KEY (id)    

) ENGINE=InnoDB 
DEFAULT CHARSET=utf8;
 
 
二、创建项目
 
依赖包结构如下先:
 
│    spring-aop.jar 

│    spring-beans.jar 

│    spring-context-support.jar 

│    spring-context.jar 

│    spring-core.jar 

│    spring-jdbc.jar 

│    spring-jms.jar 

│    spring-orm.jar 

│    spring-test.jar 

│    spring-tx.jar 

│    spring-web.jar 

│    spring-webmvc-portlet.jar 

│    spring-webmvc-struts.jar 

│    spring-webmvc.jar 

│    aspectjrt.jar 

│    aspectjweaver.jar 

│    cglib-nodep-2.1_3.jar 

│    asm-2.2.3.jar 

│    log4j-1.2.15.jar 

│    asm-commons-2.2.3.jar 

│    asm-util-2.2.3.jar 

│    aopalliance.jar 

│    mysql-connector-java-5.1.6-bin.jar 

│ 

├─log4j 

│            log4j-1.2.15.jar 

│ 

├─junit 

│            junit-3.8.2.jar 

│            junit-4.4.jar 

│            license.txt 

│ 

├─jakarta-commons 

│            commons-attributes-api.jar 

│            commons-attributes-compiler.jar 

│            commons-beanutils.jar 

│            commons-codec.jar 

│            commons-collections.jar 

│            commons-dbcp.jar 

│            commons-digester.jar 

│            commons-discovery.jar 

│            commons-fileupload.jar 

│            commons-httpclient.jar 

│            commons-io.jar 

│            commons-lang.jar 

│            commons-logging.jar 

│            commons-pool.jar 

│            commons-validator.jar 

│ 

├─jotm 

│            license.txt 

│            xapool.jar 

│            jotm-core.jar 

│            jotm-standalone.jar 

│            jotm-jms.jar 

│            jotm-datasource.jar 

│            ow2-jta-1.1-spec.jar 

│            jotm-client.jar 

│ 

├─ibatis 

│            ibatis-2.3.4.726.jar 

│            sql-map-2.dtd 

│            sql-map-config-2.dtd 

│ 

├─atomikos 

│            atomikos-util.jar 

│            transactions-api.jar 

│            transactions-essentials-all.jar 

│            transactions-hibernate2.jar 

│            transactions-hibernate3.jar 

│            transactions-jdbc-deprecated.jar 

│            transactions-jdbc.jar 

│            transactions-jms-deprecated.jar 

│            transactions-jms.jar 

│            transactions-jta.jar 

│            transactions.jar 

│ 

└─alib 

                SLF4J_LICENSE.TXT 

                jca.jar 

                jms.jar 

                jmx.jar 

                jta.jar 

                servlet-2.3.jar 

                slf4j-api-1.4.3.jar 

                slf4j-nop-1.4.3.jar
 
三、配置
 
jta.properties
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory 

com.atomikos.icatch.console_file_name = tm.out 

com.atomikos.icatch.log_base_name = tmlog 

com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm 

com.atomikos.icatch.console_log_level = INFO    
 
<?
xml 
version
="1.0" 
encoding
="UTF-8"
?> 

<!--
 局部单元测试使用,不正式发布,不要删除 --> 

<
beans 
xmlns
="http://www.springframework.org/schema/beans" 

             
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 

             
xmlns:jee
="http://www.springframework.org/schema/jee" 

             
xmlns:aop
="http://www.springframework.org/schema/aop" 

             
xmlns:tx
="http://www.springframework.org/schema/tx" 

             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 

                     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd 

                     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 

                     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
> 


        <!--
指定Spring配置中用到的属性文件--> 

        
<
bean 
id
="propertyConfig" 

                    
class
="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
> 

                
<
property 
name
="locations"
> 

                        
<
list
> 

                                
<
value
>classpath:jdbc.properties
</
value
> 

                        
</
list
> 

                
</
property
> 

        
</
bean
> 

        <!--
 数据源A --> 

        
<
bean 
id
="dataSourceA" 
class
="com.atomikos.jdbc.SimpleDataSourceBean" 
init-method
="init" 
destroy-method
="close"
> 

                
<
property 
name
="uniqueResourceName"
> 

                        
<
value
>mysql/db_a
</
value
> 

                
</
property
> 

                
<
property 
name
="xaDataSourceClassName"
> 

                        
<
value
>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
</
value
> 

                
</
property
> 

                
<
property 
name
="xaDataSourceProperties"
> 

                        
<
value
>URL=${jdbc.url};user=${jdbc.username};password=${jdbc.password}
</
value
> 

                
</
property
> 

                
<
property 
name
="exclusiveConnectionMode"
> 

                        
<
value
>true
</
value
> 

                
</
property
> 

                
<
property 
name
="connectionPoolSize"
> 

                        
<
value
>3
</
value
> 

                
</
property
> 

                
<
property 
name
="validatingQuery"
> 

                        
<
value
>SELECT 1
</
value
> 

                
</
property
> 

        
</
bean
> 

        <!--
 数据源B --> 

        
<
bean 
id
="dataSourceB" 
class
="com.atomikos.jdbc.SimpleDataSourceBean" 
init-method
="init" 
destroy-method
="close"
> 

                
<
property 
name
="uniqueResourceName"
> 

                        
<
value
>mysql/db_b
</
value
> 

                
</
property
> 

                
<
property 
name
="xaDataSourceClassName"
> 

                        
<
value
>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
</
value
> 

                
</
property
> 

                
<
property 
name
="xaDataSourceProperties"
> 

                        
<
value
>URL=${jdbc2.url};user=${jdbc2.username};password=${jdbc2.password}
</
value
> 

                
</
property
> 

                
<
property 
name
="exclusiveConnectionMode"
> 

                        
<
value
>true
</
value
> 

                
</
property
> 

                
<
property 
name
="connectionPoolSize"
> 

                        
<
value
>3
</
value
> 

                
</
property
> 

                
<
property 
name
="validatingQuery"
> 

                        
<
value
>SELECT 1
</
value
> 

                
</
property
> 

        
</
bean
> 


        
<
bean 
id
="atomikosTransactionManager" 
class
="com.atomikos.icatch.jta.UserTransactionManager" 

                    
init-method
="init" 
destroy-method
="close"
> 

                
<
property 
name
="forceShutdown" 
value
="true"
/> 

        
</
bean
> 


        
<
bean 
id
="atomikosUserTransaction" 
class
="com.atomikos.icatch.jta.UserTransactionImp"
> 

                
<
property 
name
="transactionTimeout" 
value
="300"
/> 

        
</
bean
> 

        <!--
 JTA事务管理器 --> 

        
<
bean 
id
="springTransactionManager" 
class
="org.springframework.transaction.jta.JtaTransactionManager"
> 

                
<
property 
name
="transactionManager" 
ref
="atomikosTransactionManager"
/> 

                
<
property 
name
="userTransaction" 
ref
="atomikosUserTransaction"
/> 

        
</
bean
> 



        <!--
 事务切面配置 --> 

        
<
aop:config
> 

                
<
aop:pointcut 
id
="serviceOperation" 

                                            
expression
="execution(* *..service*..*(..))"
/> 

                
<
aop:advisor 
pointcut-ref
="serviceOperation" 

                                         
advice-ref
="txAdvice"
/> 

        
</
aop:config
> 

        <!--
 通知配置 --> 

        
<
tx:advice 
id
="txAdvice" 
transaction-manager
="springTransactionManager"
> 

                
<
tx:attributes
> 

                        
<
tx:method 
name
="delete*" 
rollback-for
="Exception"
/> 

                        
<
tx:method 
name
="save*" 
rollback-for
="Exception"
/> 

                        
<
tx:method 
name
="update*" 
rollback-for
="Exception"
/> 

                        
<
tx:method 
name
="*" 
read-only
="true" 
rollback-for
="Exception"
/> 

                
</
tx:attributes
> 

        
</
tx:advice
> 


        <!--
根据dataSourceA和sql-map-config_A.xml创建一个SqlMapClientA--> 

        
<
bean 
id
="sqlMapClientA" 

                    
class
="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
> 

                
<
property 
name
="dataSource"
> 

                        
<
ref 
local
="dataSourceA"
/> 

                
</
property
> 

                
<
property 
name
="configLocation"
> 

                        
<
value
>classpath:/sql-map-config_A.xml
</
value
> 

                
</
property
> 

        
</
bean
> 

        <!--
根据dataSourceB和sql-map-config_B.xml创建一个SqlMapClientB--> 

        
<
bean 
id
="sqlMapClientB" 

                    
class
="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
> 

                
<
property 
name
="dataSource"
> 

                        
<
ref 
local
="dataSourceB"
/> 

                
</
property
> 

                
<
property 
name
="configLocation"
> 

                        
<
value
>classpath:/sql-map-config_B.xml
</
value
> 

                
</
property
> 

        
</
bean
> 

        <!--
根据sqlMapClientA创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateA--> 

        
<
bean 
id
="sqlMapClientTemplateA" 

                    
class
="org.springframework.orm.ibatis.SqlMapClientTemplate"
> 

                
<
property 
name
="sqlMapClient" 
ref
="sqlMapClientA"
/> 

        
</
bean
> 

        <!--
根据sqlMapClientB创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateB--> 

        
<
bean 
id
="sqlMapClientTemplateB" 

                    
class
="org.springframework.orm.ibatis.SqlMapClientTemplate"
> 

                
<
property 
name
="sqlMapClient" 
ref
="sqlMapClientB"
/> 

        
</
bean
> 


        <!--
 配置DAO,并注入所使用的sqlMapClientTemplate实例 --> 

        
<
bean 
id
="tabADAO" 
class
="com.lavasoft.stu.atomikos.dao.impl.TabADAOImpl"
> 

                
<
property 
name
="sqlMapClientTemplate" 
ref
="sqlMapClientTemplateA"
/> 

        
</
bean
> 

        
<
bean 
id
="tabBDAO" 
class
="com.lavasoft.stu.atomikos.dao.impl.TabBDAOImpl"
> 

                
<
property 
name
="sqlMapClientTemplate" 
ref
="sqlMapClientTemplateB"
/> 

        
</
bean
> 


        <!--
 Service配置,注入DAO --> 

        
<
bean 
id
="stuJotmService" 
class
="com.lavasoft.stu.atomikos.service.StuJotmServiceImpl"
> 

                
<
property 
name
="tabADAO" 
ref
="tabADAO"
/> 

                
<
property 
name
="tabBDAO" 
ref
="tabBDAO"
/> 

        
</
bean
> 

</
beans
>