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、准备软件环境
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
>
Oracle+Spring2.x+atomikos分布式事务配置2008-12-22 15:15<bean id="AdapterOraBean" class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>oracle1</value>
</property>
<property name="xaDataSourceClassName">
<value>oracle.jdbc.xa.client.OracleXADataSource</value>
</property>
<property name="xaDataSourceProperties">
<value>user=adapter;password=adapter;URL=jdbc:oracle:thin:@172.16.47.37:1521:hiatmpdb</value>
</property>
<property name="exclusiveConnectionMode">
<value>true</value>
</property>
<property name="connectionPoolSize">
<value>10</value>
</property>
<property name="validatingQuery">
<value>SELECT 1</value>
</property>
</bean>
<bean id="PunishOraBean" class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>oracle2</value>
</property>
<property name="xaDataSourceClassName">
<value>oracle.jdbc.xa.client.OracleXADataSource</value>
</property>
<property name="xaDataSourceProperties">
<value>user=NLV_GUEST;password=GUEST;URL=jdbc:oracle:thin:@172.16.47.37:1521:hiatmpdb</value>
</property>
<property name="exclusiveConnectionMode">
<value>true</value>
</property>
<property name="connectionPoolSize">
<value>10</value>
</property>
<property name="validatingQuery">
<value>SELECT 1</value>
</property>
</bean>
<!--分别配置访问AdapterOraBean、PunishOraBean数据源的Spring JDBC模板-->
<bean id="adapterJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="AdapterOraBean"/>
</bean>
<bean id="punishJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="PunishOraBean"/>
</bean>
<!-- 定义本地实例 -->
<bean id = "atomikosTransactionManager" class ="com.atomikos.icatch.jta.UserTransactionManager" init-method = "init" destroy-method = "close" >
<property name = "forceShutdown">
<value>true</value>
</property>
</bean>
<bean id = "atomikosUserTransaction" class = "com.atomikos.icatch.jta.UserTransactionImp">
<property name = "transactionTimeout" value = "120"/>
</bean>
<!-- JTA事务管理器 -->
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name = "transactionManager">
<ref bean = "atomikosTransactionManager"/>
</property >
<property name = "userTransaction">
<ref bean = "atomikosUserTransaction"/>
</property >
</bean>
<!-- tx事务工厂类 -->
<bean id="atomikosTransactionProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager">
<ref bean="txManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true" />
<!--分别配置基于模板AdapterOraBean,PunishOraBean的DAO-->
<bean id="TableTest" class="com.hisense.adapter.util.TableTest">
<property name="jdbcTemplate" ref="adapterJdbcTemplate"/>
</bean>
<bean id="ProcedureTest" class="com.hisense.adapter.util.ProcedureTest">
<property name="jdbcTemplate" ref="punishJdbcTemplate"/>
</bean>
<!--跨数据库的JTA事务的业务类-->
<bean id="CallableTest" parent="atomikosTransactionProxy">
<property name="target">
<bean class="com.hisense.adapter.util.CallableTest">
<property name="tableTest"> <ref bean="TableTest"/></property>
<property name="procedureTest"> <ref bean="ProcedureTest"/></property>
</bean>
</property>
</bean>