环境
- Spring:3.1;
- Mybatis:3.1;
- 数据库:我这里是不存在主从关系的、相互独立的两个oracle数据库;
需求
系统本身是Oracle数据库,但是系统中的个别功能是查询另外的数据库(我这里是echarts指标展示图部分),因此需要对mybatis进行配置,需要同时连接两个数据库,这两个数据库之间不存在任何关系。
实现
简单的在配置文件里再添加一个datasource的bean、sqlSessionFactory、mapperScannerConfigurer和transactionManager,把数据库连接信息改一下的方式是行不通的,这里是使用Spring提供的AbstractRoutingDataSource类来根据请求路由到不同的数据源。
1.Mybatis配置文件
<!-- 引入jdbc配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--动态数据源dataSource-->
<bean id="dynamicDataSource" class="com.cdsoft.platform.common.DynamicDataSource" >
<property name="targetDataSources">
<map key-type="java.lang.String">
<!--通过不同的key决定用哪个dataSource-->
<entry value-ref="dataSource" key="dataSource"></entry>
<entry value-ref="dataSourceEcharts" key="dataSourceEcharts"></entry>
</map>
</property>
<!--设置默认的dataSource-->
<property name="defaultTargetDataSource" ref="dataSource">
</property>
</bean>
<!--创建jdbc数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<!--echarts指标展示数据源配置-->
<bean id="dataSourceEcharts" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${echarts.url}" />
<property name="username" value="${echarts.username}" />
<property name="password" value="${echarts.password}" />
</bean>
<!-- 创建SqlSessionFactory,同时指定数据源 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource" />
</bean>
<!-- 可通过注解控制事务 -->
<tx:annotation-driven/>
<!-- Mapper接口所在包名,Spring会自动查找其下的Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cdsoft.*.mapper,com.cdsoft.mcm.*.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
2.利用ThreadLocal解决线程安全问题,实现各个数据源之间的切换
package com.cdsoft.platform.common;
import org.apache.commons.lang.StringUtils;
public class CustomerContextHolder {
public static final String DATA_SOURCE_BASIC = "dataSource";
public static final String DATA_SOURCE_ECHARTS = "dataSourceEcharts";
//用ThreadLocal来设置当前线程使用哪个dataSource
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
String dataSource = contextHolder.get();
if (StringUtils.isEmpty(dataSource)) {
return DATA_SOURCE_BASIC;
} else {
return dataSource;
}
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
3.继承Spring的AbstractRoutingDataSource类,并实现determineCurrentLookupKey方法
package com.cdsoft.platform.common;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
4.在service层或dao层进行使用
package com.cdsoft.mcm.index.service.impl;
import com.cdsoft.mcm.index.mapper.QueryIndexMapper;
import com.cdsoft.mcm.index.service.IQueryIndexService;
import com.cdsoft.platform.common.CustomerContextHolder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
@Service
public class QueryIndexServiceImpl implements IQueryIndexService {
@Resource
private QueryIndexMapper queryIndexMapper;
@Override
public List<HashMap> queryChSzIndex(HashMap params) {
System.out.println(CustomerContextHolder.getCustomerType()+"===============datasource");
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_ECHARTS);
System.out.println(CustomerContextHolder.getCustomerType()+"===============datasource");
return queryIndexMapper.queryChSzIndex(params);
}
}
到此,就实现了两个数据库之间的正常切换。
参考文章: