1.与无事务版的一样,创建DynamicDataSource类,继承AbstractRoutingDataSource
package com.test.main.dataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
创建辅助类DynamicDataSourceHolder,主要用于保存当前线程所需的datasource的key值
package com.test.main.dataSource;
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();
public static String getDataSource() {
return THREAD_DATA_SOURCE.get();
}
public static void setDataSource(String dataSource) {
THREAD_DATA_SOURCE.set(dataSource);
}
public static void clearDataSource() {
THREAD_DATA_SOURCE.remove();
}
}
创建dao层切面,注解选择数据源DataSourceAspect类:
package com.test.main.dataSource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.test.main.annotations.DataSource;
@Component
@Aspect
public class DataSourceAspect {
@Before("execution(* com.test.model.dao.*.*.*(..))")
public void intercept(JoinPoint point) throws Exception {
Class<?> target = point.getTarget().getClass();
MethodSignature signature = (MethodSignature) point.getSignature();
for (Class<?> clazz : target.getInterfaces()) {
resolveDataSource(clazz, signature.getMethod());
}
resolveDataSource(target, signature.getMethod());
}
private void resolveDataSource(Class<?> clazz, Method method) {
String sourceName = null;
try {
Class<?>[] types = method.getParameterTypes();
if (clazz.isAnnotationPresent((Class<? extends Annotation>) DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
sourceName = source.value();
DynamicDataSourceHolder.setDataSource(sourceName);
}
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
sourceName = source.value();
DynamicDataSourceHolder.setDataSource(sourceName);
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
2.spring-db.xml 配置:
<?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:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<util:properties id="jdbc"
location="classpath:etc/mybatis/db.properties" />
<!-- 连接池配置开始 -->
<bean id="chicken" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="uniqueResourceName" value="mysql/chicken" />
<property name="xaProperties">
<props>
<prop key="user">#{jdbc.username}</prop>
<prop key="password">#{jdbc.password}</prop>
<prop key="url">#{jdbc.chicken}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="test_chicken" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="uniqueResourceName" value="mysql/test_chicken" />
<property name="xaProperties">
<props>
<prop key="user">#{jdbc.username}</prop>
<prop key="password">#{jdbc.password}</prop>
<prop key="url">#{jdbc.c_test}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="fariyking" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="uniqueResourceName" value="mysql/fariyking" />
<property name="xaProperties">
<props>
<prop key="user">#{jdbc.username}</prop>
<prop key="password">#{jdbc.password}</prop>
<prop key="url">#{jdbc.fariyking}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="test_fariyking" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="uniqueResourceName" value="mysql/test_fariyking" />
<property name="xaProperties">
<props>
<prop key="user">#{jdbc.username}</prop>
<prop key="password">#{jdbc.password}</prop>
<prop key="url">#{jdbc.f_test}</prop>
</props>
</property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="60" />
<property name="reapTimeout" value="20000" />
</bean>
<!-- 连接池配置结束 -->
<!-- MyBatis整合开始 -->
<bean id="c_dynamicDataSource" class="com.test.main.dataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="chicken" value-ref="chicken"></entry>
<entry key="test_chicken" value-ref="test_chicken"></entry>
</map>
</property>
</bean>
<bean id="cFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="c_dynamicDataSource" />
<property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
<property name="mapperLocations" value="classpath:com/test/**/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.model.dao.c" />
<property name="annotationClass" value="com.test.main.annotations.MyBatisRepository" />
<property name="sqlSessionFactory" ref="cFactory"></property>
<property name="sqlSessionFactoryBeanName" value="cFactory"></property>
</bean>
<bean id="f_dynamicDataSource" class="com.test.main.dataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="fariyking" value-ref="fariyking"></entry>
<entry key="test_fariyking" value-ref="test_fariyking"></entry>
</map>
</property>
</bean>
<bean id="fFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="f_dynamicDataSource" />
<property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
<property name="mapperLocations" value="classpath:com/test/**/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.model.dao.f" />
<property name="annotationClass" value="com.test.main.annotations.MyBatisRepository" />
<property name="sqlSessionFactory" ref="fFactory"></property>
<property name="sqlSessionFactoryBeanName" value="fFactory"></property>
</bean>
<!-- MyBatis整合结束 -->
<!-- 配置数据库事务开始 -->
<!-- atomikos事务管理器 -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<description>UserTransactionManager</description>
<property name="forceShutdown">
<value>true</value>
</property>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="3000" />
</bean>
<bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref bean="atomikosTransactionManager" />
</property>
<property name="userTransaction">
<ref bean="atomikosUserTransaction" />
</property>
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<tx:annotation-driven transaction-manager="springTransactionManager" />
<!-- 配置数据库事务结束 -->
</beans>
2.1在同一个事务中,不同的数据源需要不同 SqlSessionFactoryBean,注意配置时,需要配置 MapperScannerConfigurer的:
<property name="sqlSessionFactoryBeanName" value="cFactory"></property>
value值为:SqlSessionFactoryBean 的 bean id;
2.2同一事务中的SqlSessionFactoryBean,对应MapperScannerConfigurer 中的 basePackage 不能范围重合,不然在同一事务时,spring不会切换数据源,而是取先前与之重合的SqlSessionFactoryBean的数据源
本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/2046456,如需转载请自行联系原作者