最近有点时间 , 就准备搭个多库事务的例子 , 不过中间碰到一些问题 , 这里记录下来 .
我的atomikos 版本是 3.7.0 ; Spring4 mybatis3 ;
碰到问题主要有两类 :
1 : 缺少依赖jar包
atomikos-util.jar
transactions.jar
transactions-jta.jar
transactions-jdbc-deprecated.jar
mybatis.jar
mybatis-spring.jar
cglib.2.2.2.jar
jta.jar
2 : 配置文件编写错误
开始网上down了个配置 , 如下 :
<
bean
id
=
"dataSource"
class
=
"com.atomikos.jdbc.SimpleDataSourceBean"
init-method
=
"init"
destroy-method
=
"close"
>
<
property
name
=
"uniqueResourceName"
value
=
"mysql/main"
/>
<
property
name
=
"xaDataSourceClassName"
value
=
"com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"
/>
<
property
name
=
"xaDataSourceProperties"
value
=
"URL=${jdbc.url.a};user=${jdbc.username.a};password=${jdbc.password.a}"
/>
<
property
name
=
"exclusiveConnectionMode"
value
=
"true"
/>
<
property
name
=
"connectionPoolSize"
value
=
"10"
/>
<
property
name
=
"validatingQuery"
>
<
value
>SELECT 1</
value
>
</
property
>
</
bean
>
额 ... 这个跑起来是报错的 .........
ds应该酱紫写 :
<bean name="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>ds1</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL">${ds1.jdbc.url}</prop>
<prop key="user">${ds1.jdbc.username}</prop>
<prop key="password">${ds1.jdbc.password}</prop>
</props>
</property>
<property name="poolSize"><value>1</value></property>
<property name="maxPoolSize"><value>30</value></property>
</bean>
<bean name="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>ds2</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="URL">${ds2.jdbc.url}</prop>
<prop key="user">${ds2.jdbc.username}</prop>
<prop key="password">${ds2.jdbc.password}</prop>
</props>
</property>
<property name="poolSize"><value>1</value></property>
<property name="maxPoolSize"><value>30</value></property>
</bean>
然后mysql建两个库 , test1 , test2 , 库里各建一张表 t1 , t2 ;
CREATE TABLE `t1` (
`c1` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c2` varchar(100) NOT NULL,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
接下来就是spring和mybatis的配置了 , 一路走下来就没什么难点了 ;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<context:property-placeholder location="classpath:config.properties" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
<context:annotation-config/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:component-scan base-package="my.service"/>
</beans>
注解配置 ↑ .....
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-autowire="byName" default-lazy-init="false"> <bean name="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close"> <property name="uniqueResourceName"> <value>ds1</value> </property> <property name="xaDataSourceClassName"> <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value> </property> <property name="xaProperties"> <props> <prop key="URL">${ds1.jdbc.url}</prop> <prop key="user">${ds1.jdbc.username}</prop> <prop key="password">${ds1.jdbc.password}</prop> </props> </property> <property name="poolSize"><value>1</value></property> <property name="maxPoolSize"><value>30</value></property> </bean> <bean name="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close"> <property name="uniqueResourceName"> <value>ds2</value> </property> <property name="xaDataSourceClassName"> <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value> </property> <property name="xaProperties"> <props> <prop key="URL">${ds2.jdbc.url}</prop> <prop key="user">${ds2.jdbc.username}</prop> <prop key="password">${ds2.jdbc.password}</prop> </props> </property> <property name="poolSize"><value>1</value></property> <property name="maxPoolSize"><value>30</value></property> </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="300" /> </bean> <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager"> <ref bean="atomikosTransactionManager" /> </property> <property name="userTransaction"> <ref bean="atomikosUserTransaction" /> </property> </bean> <aop:aspectj-autoproxy /> <aop:config proxy-target-class="true"> <aop:advisor pointcut="execution(* *my.service..*(..))" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="springTransactionManager"> <tx:attributes> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="has*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" /> </tx:attributes> </tx:advice> </beans>ds配置 ↑ ..........
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-autowire="byName" default-lazy-init="false"> <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <property name="dataSource" ref="dataSource1"/> <property name="mapperLocations"> <list> <value>classpath*:*-mapper1.xml</value> </list> </property> </bean> <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <property name="dataSource" ref="dataSource2"/> <property name="mapperLocations"> <list> <value>classpath*:*-mapper2.xml</value> </list> </property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="my.mapper1"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"></property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="my.mapper2"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"></property> </bean> </beans>spring-mybatis 集成 ↑ ..........
需要注意的是还需要在classpath下新建一个jta.properties
内容可以参考这个 , 根据实际场景做修改
# SAMPLE PROPERTIES FILE FOR THE TRANSACTION SERVICE # THIS FILE ILLUSTRATES THE DIFFERENT SETTINGS FOR THE TRANSACTION MANAGER # UNCOMMENT THE ASSIGNMENTS TO OVERRIDE DEFAULT VALUES; # Required: factory implementation class of the transaction core. # NOTE: there is no default for this, so it MUST be specified! # com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory # Set base name of file where messages are output # (also known as the 'console file'). # com.atomikos.icatch.console_file_name = tm.out # Size limit (in bytes) for the console file; # negative means unlimited. # # com.atomikos.icatch.console_file_limit=-1 # For size-limited console files, this option # specifies a number of rotating files to # maintain. # # com.atomikos.icatch.console_file_count=1 # Set the number of log writes between checkpoints # # com.atomikos.icatch.checkpoint_interval=500 # Set output directory where console file and other files are to be put # make sure this directory exists! # # com.atomikos.icatch.output_dir = ./ # Set directory of log files; make sure this directory exists! # # com.atomikos.icatch.log_base_dir = ./ # Set base name of log file # this name will be used as the first part of # the system-generated log file name # com.atomikos.icatch.log_base_name = tmlog # Set the max number of active local transactions # or -1 for unlimited. # # com.atomikos.icatch.max_actives = 50 # Set the default timeout (in milliseconds) for local transactions # # com.atomikos.icatch.default_jta_timeout = 10000 # Set the max timeout (in milliseconds) for local transactions # # com.atomikos.icatch.max_timeout = 300000 # The globally unique name of this transaction manager process # override this value with a globally unique name # com.atomikos.icatch.tm_unique_name = tm # Do we want to use parallel subtransactions? JTA's default # is NO for J2EE compatibility # # com.atomikos.icatch.serial_jta_transactions=true # If you want to do explicit resource registration then # you need to set this value to false. # # com.atomikos.icatch.automatic_resource_registration=true # Set this to WARN, INFO or DEBUG to control the granularity # of output to the console file. # com.atomikos.icatch.console_log_level=INFO # Do you want transaction logging to be enabled or not? # If set to false, then no logging overhead will be done # at the risk of losing data after restart or crash. # # com.atomikos.icatch.enable_logging=true # Should two-phase commit be done in (multi-)threaded mode or not? # Set this to false if you want commits to be ordered according # to the order in which resources are added to the transaction. # # NOTE: threads are reused on JDK 1.5 or higher. # For JDK 1.4, thread reuse is enabled as soon as the # concurrent backport is in the classpath - see # http://mirrors.ibiblio.org/pub/mirrors/maven2/backport-util-concurrent/backport-util-concurrent/ # # com.atomikos.icatch.threaded_2pc=false # Should shutdown of the VM trigger shutdown of the transaction core too? # # com.atomikos.icatch.force_shutdown_on_vm_exit=false写两个测试用的mapper
@Repository("testMapper1")
public interface TestMapper1 {
int testMethod();
void insertT1WithException();
void insertT1WithOutException(String s);
}
@Repository("testMapper2")
public interface TestMapper2 {
int testMethod();
void insertT2WithException();
void insertT2WithOutException(String s);
}
service ............
@Service
public class TestService {
@Resource
private TestMapper1 testMapper1;
@Resource
private TestMapper2 testMapper2;
public void test(){
String s = UUID.randomUUID().toString();
testMapper1.insertT1WithOutException(s);
// testMapper1.insertT1WithException();
// testMapper2.insertT2WithOutException(s);
testMapper2.insertT2WithException();
}
}
然后在testcase里调用 :
insertT1WithOutException为正常操作 ,
insertT1WithException则会抛出异常 ,
System.out.println("begin");
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-*.xml");
TestService testService = (TestService) ctx.getBean("testService");
testService.test();
System.out.println("end");
执行结果如下 , 可以看到两个操作都回滚了 ╮(╯▽╰)╭
DEBUG org.springframework.transaction.jta.JtaTransactionManager Initiating transaction rollback DEBUG atomikos getCompositeTransaction() returning instance with id tm0000100023 DEBUG atomikos getCompositeTransaction() returning instance with id tm0000100023 DEBUG atomikos getCompositeTransaction() returning instance with id tm0000100023 DEBUG atomikos getCompositeTransaction() returning instance with id tm0000100023 INFO atomikos XAResource.rollback ( 746D30303030313030303233:746D31 ) on resource ds1 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@4b6690c0 INFO atomikos XAResource.rollback ( 746D30303030313030303233:746D32 ) on resource ds2 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@6b8d96d9 INFO atomikos rollback() done of transaction tm0000100023
=============================================================================================================
代码传到csdn了 , 不过多了很多无用的jar包 , 大家可以删掉 , 地址 : http://download.csdn.net/detail/ayanami001/9108113
还有个根据数据库自动生成mapper , xml , 以及service接口的小工具 , 基于ftl , 也分享给大家 ╮(╯▽╰)╭
http://download.csdn.net/detail/ayanami001/9104585
=============================================================================================================