1、src/main/resources/application.properties 中配置好多个数据源
spring.datasource.initialize=false
#接口请求端口号、路径
server.port=9090
servcer.context-path=/
#mybatis配置
#mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml
#oracle数据库数据源信息
oracle.datasource.driverClassName=oracle.jdbc.OracleDriver
oracle.datasource.url=jdbc:oracle:thin:@ip/dbname
oracle.datasource.username=user
oracle.datasource.password=pwd
#mysql数据库数据源信息
mysql.datasource.jdbc.driverClassName=com.mysql.jdbc.Driver
mysql.datasource.jdbc.url=jdbc:mariadb://ip:3306/dbname
mysql.datasource.jdbc.username=user
mysql.datasource.jdbc.password=pwd
2、定义一个枚举类型 DatabaseType.java,表示不同的环境
package com.twf.springBootDemo.util;
/**
* @author tianwf
* @date 2020/12/30 9:58
* oracle oracle数据库环境
* mysql mysql数据库环境
*/
public enum DatabaseType {
oracle("oracle", "1"), mysql("mysql", "2");
private String name;
private String value;
DatabaseType(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
3、定义一个 DatabaseContextHolder.java, 保存一个线程安全的DatabaseType容器
package com.twf.springBootDemo.dataSourceConfig;
import com.twf.springBootDemo.util.DatabaseType;
/**
* @author tianwf
* @date 2020/12/30 10:00
* 保存一个线程安全的DatabaseType容器
*/
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
public static void setDatabaseType(DatabaseType databaseType) {
contextHolder.set(databaseType);
}
public static DatabaseType getDatabaseType() {
return contextHolder.get();
}
}
4、定义动态数据源获取的方法 DynamicDataSource.java,集成 AbstractRoutingDataSource
package com.twf.springBootDemo.dataSourceConfig;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @author tianwf
* @date 2020/12/30 10:15
* 动态数据源(需要继承AbstractRoutingDataSource)
* 使用DatabaseContextHolder获取当前线程的DatabaseType
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
}
5、mybatis多数据源的配置 MybatisConfig.java
package com.twf.springBootDemo.dataSourceConfig;
import com.alibaba.druid.pool.DruidDataSource;
import com.twf.springBootDemo.util.DatabaseType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author tianwf
* @date 2020/12/30 10:21
* mybatis多数据源的配置,springboot集成mybatis基本入口
* 1、创建数据源
* 2、创建SqlSessionFactory
*/
@Configuration
@MapperScan(basePackages = "com.twf.springBootDemo.mapper", sqlSessionFactoryRef = "sessionFactory")
public class MybatisConfig {
/*mapper.xml路径*/
@Value("${mybatis.mapper-locations}")
private String mapperPath;
/*oracle驱动*/
@Value("${oracle.datasource.driverClassName}")
private String oradbDriver;
/*oracle数据库连接地址*/
@Value("${oracle.datasource.url}")
private String oraUrl;
/*oracle数据库连接用户名*/
@Value("${oracle.datasource.username}")
private String oraUsername;
/*oracle数据库连接密码*/
@Value("${oracle.datasource.password}")
private String oraPassword;
/*mysql驱动*/
@Value("${mysql.datasource.jdbc.driverClassName}")
private String mysqldbDriver;
/*mysql数据库连接地址*/
@Value("${mysql.datasource.jdbc.url}")
private String mysqlUrl;
/*mysql数据库连接用户名*/
@Value("${mysql.datasource.jdbc.username}")
private String mysqlUsername;
/*mysql数据库连接密码*/
@Value("${mysql.datasource.jdbc.password}")
private String mysqlPassword;
/**
* 创建 oracle环境 dataSource
* @throws Exception
*/
@Bean(name = "dataSourceOracle")
public DataSource dataSourceOracle() throws Exception {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(oradbDriver);
dataSource.setUrl(oraUrl);
dataSource.setUsername(oraUsername);
dataSource.setPassword(oraPassword);
return dataSource;
}
/**
* 创建 mysql环境 dataSource
* @throws Exception
*/
@Bean(name="dataSourceMysql")
public DataSource dataSourceMysql() throws Exception {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(mysqldbDriver);
dataSource.setUrl(mysqlUrl);
dataSource.setUsername(mysqlUsername);
dataSource.setPassword(mysqlPassword);
return dataSource;
}
/**
* 1、创建动态数据源
* @throws Exception
* @Primary该注解表示在同一个接口有多个类可以注入的时候,默认选择哪个,而不是让@Autowired报错
*/
@Bean(name="dynamicDataSource")
@Primary
public DynamicDataSource dynamicDataSource(
@Qualifier("dataSourceOracle") DataSource dataSourceOracle,
@Qualifier("dataSourceMysql") DataSource dataSourceMysql
) throws Exception {
Map<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put(DatabaseType.oracle, dataSourceOracle);
targetDataSource.put(DatabaseType.mysql, dataSourceMysql);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSource);
dynamicDataSource.setDefaultTargetDataSource(dataSourceOracle);
return dynamicDataSource;
}
/**
* 根据数据源创建SqlSessionFactory
* @throws Exception
*/
@Bean(name="sessionFactory")
public SqlSessionFactory sessionFactory(
@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
PathMatchingResourcePatternResolver pmrpr = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(pmrpr.getResources(mapperPath));//*Mapper.xml位置
return sqlSessionFactoryBean.getObject();
}
}
6、修改服务类 StudentService.java:添加环境切换方法setDataSourceByEnvironment,同时在获取数据的方法中切换数据源
package com.twf.springBootDemo.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.twf.springBootDemo.dataSourceConfig.DatabaseContextHolder;
import com.twf.springBootDemo.entity.Customer;
import com.twf.springBootDemo.mapper.CustomerMapper;
import com.twf.springBootDemo.service.WebService;
import com.twf.springBootDemo.util.DatabaseType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@MapperScan("com.twf.springBootDemo.mapper")
public class WebServiceImpl implements WebService {
@Resource
private CustomerMapper customerMapper;
public void setDataSourceByEnvironment(String environment) {
//oracle数据源
if(environment.equals(DatabaseType.oracle.getValue())) {
DatabaseContextHolder.setDatabaseType(DatabaseType.oracle);
} else if(environment.equals(DatabaseType.mysql.getValue())) {//mysql数据源
DatabaseContextHolder.setDatabaseType(DatabaseType.mysql);
}
}
@Override
public String helloWorld(String params) {
System.out.println("====" + params);
setDataSourceByEnvironment("1");
List<Customer> customerList = customerMapper.getCustomerList();
// System.out.println(customerList.size());
if(customerList.size() > 0) {
for(int i = 0; i < customerList.size(); i++) {
Customer customer = customerList.get(i);
System.out.println(customer.getName());
}
}
return result;
}
}
7、SpringBoot配置多数据源,会引发循环引用问题
修改方案:在Spring boot启动的时候排除DataSourceAutoConfiguration,并另外导入MyBatisConfig
@Import({MybatisConfig.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})