因为架构升级,导致同样的功能在两套完全的里的系统中分别提供,又因为不能完全切换,所以系统1.0和系统2.0的数据要做到同步,所以为实现数据一致性,所以开发了一套数据同步系统,涉及到了多个数据源,调试过程中有数据异常导致的部分数据没有插入成功,但是存在数据没有回滚的情况。

1、本类调用@Transactional注解的方法事务不其中用,因为采用Spring的注解方式(aop)实现事务控制,aop的实现无论是使用动态代理还是织入方式都是通过对业务类包装实现的,当内部方法调用时,不会使用包装类的实现,所以不会引入事务,如下代码所示:
[pre]

[code lang=”java”]
public class TransactionInvoker {
private TrancationCallee trancationCallee;
/**
*
* @Title testNotTransaction
* @Description 事务没有作用
*
*/
public void testNotTransaction() {
trancationCallee.notTrancation();
}
/**
*
* @Title testTransaction
* @Description 事务有作用
*
*/
public void testTransaction() {
trancationCallee.trancaction();
}
}

public class TrancationCallee {
public void notTrancation() {
this.trancaction();
}
@Transactional
public void trancaction() {
}
}
[/code]

[/pre]
2、部分数据库引擎不支持事务,比如Mysql的Myisam引擎。
检查表引擎是否支持,mysql查询创建语句:
show create table 表名;
可以从建表语句上查看该表的数据库引擎

3、Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是unchecked
如果遇到checked意外就不回滚。
如何改变默认规则:
a、让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)
b、让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

4、多数据源事务回滚,Spring的默认事务控制,只能绑定一个数据源,因此当多个数据数据源时,同时配置多个事务控制只有一个会有作用,因此当异常触发回滚时,只回滚第一个事务配置绑定的数据源的sql,没有实现多数据源的异常回滚。
解决办法,使用JTA可以实现多数据源的事务控制,但是大多数JTA需要使用JNDI,需要应用服务器(tomcat)等上做配置。atomikos提供了在应用中配置实现JTA事务控制的方法。
涉及改动的配置如下:
数据源的配置:
[pre]

[code lang=”xml”]
<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="dataSource" />
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="url">${jdbc_url}</prop>
<prop key="user">${jdbc_username}</prop>
<prop key="password">${jdbc_password}</prop>
</props>
</property>
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="5" />
<property name="borrowConnectionTimeout" value="350" />
<property name="testQuery" value="select 1" />
<property name="maintenanceInterval" value="60" />
</bean>
[/code]

[/pre]
事务配置:
[pre]

[code lang=”xml”]
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown">
<value>false</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>
<tx:annotation-driven transaction-manager="springTransactionManager" />
[/code]

[/pre]
其他的配置保持不变:
[pre]

[code lang=”xml”]
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-configs.xml"></property>
<property name="mapperLocations" value="classpath:mybatis/sqlmaps/*.xml"></property>
<property name="typeAliasesPackage" value="com.xxxx.po" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxxx.dao" />
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
[/code]

[/pre]
记得在开启注解扫描和需要事务的方法上添加@Transactional