Spring+iBatis+Atomikos实现JTA事务
实现分布式事务管理
网上有很多都是配置2甚至多个一样的Dao去实现此操作,小弟修改了一下ibatis源代码使得dao层可以动态指定数据源。
Spring配置文件
<tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="delete*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="*" read-only="true" /></tx:attributes></tx:advice><aop:config><aop:pointcut id="allManagerMethod"expression="execution (* com.test.*.*.service.*.*(..))" /><aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" /></aop:config><!--配置jta transactionManager--><bean id="transactionManager" /> </property> <property name="userTransaction"> <ref bean="atomikosUserTransaction" /> </property> <property name="allowCustomIsolationLevels" value="true"/></bean> <bean id="atomikosTransactionManager" init-method="init" destroy-method="close"> <property name="forceShutdown"> <value>true</value> </property> </bean><bean id="atomikosUserTransaction" init-method="init" destroy-method="close"> <property name="uniqueResourceName"> <value>oracle/read</value> </property> <property name="xaDataSourceClassName"> <value>oracle.jdbc.xa.client.OracleXADataSource</value> </property> <property name="xaProperties"> <props> <prop key="user">customer</prop> <prop key="password">123456</prop> <prop key="URL">jdbc:oracle:thin:@localhost:1521:jddb</prop> </props> </property> <property name="maxPoolSize"><value>10</value></property> <property name="minPoolSize"><value>2</value></property> <property name="loginTimeout"><value>30</value></property> <property name="reapTimeout"><value>20000</value></property> <property name="testQuery"> <value>select 1 from dual</value> </property> </bean><bean id="datasource2" init-method="init" destroy-method="close"> <property name="uniqueResourceName"> <value>oracle/read</value> </property> <property name="xaDataSourceClassName"> <value>oracle.jdbc.xa.client.OracleXADataSource</value> </property> <property name="xaProperties"> <props> <prop key="user">customer</prop> <prop key="password">123456</prop> <prop key="URL">jdbc:oracle:thin:@192.168.0.2:1521:jddb</prop> </props> </property> <property name="maxPoolSize"><value>10</value></property> <property name="minPoolSize"><value>2</value></property> <property name="loginTimeout"><value>30</value></property> <property name="reapTimeout"><value>20000</value></property> <property name="testQuery"> <value>select 1 from dual</value> </property> </bean><!--配置 sqlMapClient --><bean id="sqlMapClient" value="classpath:sqlMapConfig.xml"></property> <property name="dataSource" ref="datasource1" /> </bean> <bean id="sqlMapClient2" value="classpath:sqlMapConfig2.xml"></property> <property name="dataSource" ref="datasource2" /> </bean><!-- 增加此属性,为了在dao层和service动态分配sqlMapClient --><bean id="sqlMapClientMap" value-ref="sqlMapClient" /> <entry key="WRITE" value-ref="sqlMapClient2" /> </map> </property></bean>
public class SqlMapClientMap {private LinkedHashMap<String,SqlMapClient> map = new LinkedHashMap<String,SqlMapClient>();public LinkedHashMap<String,SqlMapClient> getMap() {return map;}public void setMap(LinkedHashMap<String,SqlMapClient> map) {this.map = map;}}
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactorycom.atomikos.icatch.console_file_name = tm.outcom.atomikos.icatch.log_base_name = tmlogcom.atomikos.icatch.tm_unique_name = tmcom.atomikos.icatch.console_log_level=INFO
//当前调用sqlMap名称protected String sqlMapClientName;//配置文件注入sqlMap集合private SqlMapClientMap sqlMapClientMap = new SqlMapClientMap();
public final SqlMapClientTemplate getSqlMapClientTemplate() { if(sqlMapClientName == null) { } else { SqlMapClient sqlMapClient = sqlMapClientMap.getMap().get(sqlMapClientName); this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient); } return this.sqlMapClientTemplate;}
public class DataSourceContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();public static void setCustomerType(String customerType) {contextHolder.set(customerType);}public static String getCustomerType() {return (String) contextHolder.get();}public static void clearCustomerType() {contextHolder.remove();}}public class DataSourceMap {public static final String READ1 = "READ1";public static final String WRITE = "WRITE";}Dao层代码@Component("iFunocxDao")public class FunocxDao extends SqlMapClientDaoSupport implements IFunocxDao {public void insert(Object o) {// TODO Auto-generated method stub sqlMapClientName = DataSourceContextHolder.getCustomerType();getSqlMapClientTemplate().insert(o)}}Service层代码@Service("iFunocxService")public class FunocxService implements IFunocxService {@Autowiredprivate IFunocxDao iFunocxDao;public void insert(Funocx ocx) {// TODO Auto-generated method stub DataSourceContextHolder.setCustomerType(DataSourceMap.WRITE); iFunocxDao.insert(ocx); DataSourceContextHolder.setCustomerType(DataSourceMap.WRITE); iFunocxDao.insert(ocx);}}