spring + mybatis 多数据源配置解决方案
配置多个不同的数据源,使用一个sessionFactory,在业务逻辑使用的时候自动切换到不同的数据源。
最近公司项目需求多数据源实现,以防忘记,记录下来方便下次查看。
首先是在applicationContext.xml里面配置多个数据源,我这里配置了两个。
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxxx" p:username="root"
p:password="root">
<property name="validationQuery">
<value>SELECT 1</value>
</property>
<property name="testOnBorrow">
<value>true</value>
</property>
</bean>
<!-- 配置CRM数据源 -->
<bean id="dataSourceCrm"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxxx" p:username="root"
p:password="root">
<property name="validationQuery">
<value>SELECT 1</value>
</property>
<property name="testOnBorrow">
<value>true</value>
</property>
</bean>
添加DatabaseContextHolder,用来保存当前应该使用的数据源名称:
package com.core.dynamic;
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();
}
}
添加AbstractRoutingDataSource实现类,实现数据源路由选择:
package com.core.dynamic;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Bean
@Override
protected Object determineCurrentLookupKey() {
// 从自定义的位置获取数据源标识
return DynamicDataSourceHolder.getDataSource();
}
}
然后回到applicationContext.xml里面,配置动态数据源:
<bean id="dynamicDataSource"
class="com.core.dynamic.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和与之对应的数据源 -->
<entry key="dataSource" value-ref="dataSource"></entry>
<entry key="dataSourceCrm" value-ref="dataSourceCrm"></entry>
</map>
</property>
<!-- 这里可以指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource" />
</bean>
配置sessionFactory
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="mapperLocations"
value="classpath:com/*/dao/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.*.dao" />
</bean>
配置事务管理器及通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dynamicDataSource" />
<!-- 通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression="execution(* com.*.service..*(..)))" />
<aop:advisor pointcut-ref="serviceMethod"
advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice"
transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
双数据源使用方法
package com.core.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.core.dao.CrmUserDao;
import com.core.dynamic.DynamicDataSourceHolder;
import com.core.entity.CrmUser;
@Service
public class CrmUserService{
@Autowired
private CrmUserDao crmUserDao;
public CrmUser listById(CrmUser user){
//切换数据源
DynamicDataSourceHolder.setDataSource("dataSourceCrm");
return crmUserDao.listById(user);
}
}
补充:项目后期运行的时候报错提示找不到我所新建的dynamicDataSource类需要在配置文件中扫描配置上加上你的类目录
<!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
<context:component-scan base-package="com.*.dao" />
<context:component-scan base-package="com.*.dynamic" />
总结:双数据源配置实现起来过程并不是很复杂,细心就好,切换数据源的方法也可以将他封装成注解的方式,这里就不细说了,自己项目中因为所用到的双数据源的地方并不多,所以就没有去配置,有想法的朋友可以上网查找,网上有很多基于注解的方式切换数据源的文章。