引入依赖
<!-- jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
如果需要使用到其他数据库,则引入其他需要的依赖,不过Oracle不能直接引入使用了,需要自己下载jar包引入到项目中
yml配置默认的数据源:
spring:
datasource:
default:
url: jdbc:mysql://localhost:3306/myproj?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
driverClassName: com.mysql.cj.jdbc.Driver
maxActive: 20
initialSize: 5
testWhileIdle: true
testOnReturn: true
testOnBorrow: true
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 30000
validationQuery: SELECT 1 FROM DUAL
minIdle: 3
poolPreparedStatements: true
logAbandoned: true
removeAbandoned: true
removeAbandonedTimeout: 1800
filters: stat,wall
接着我们配置默认数据源
import com.alibaba.druid.pool.DruidDataSource;
import com.datasource.DynamicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
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.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.default.url}")
private String defaultDBUrl;
@Value("${spring.datasource.default.username}")
private String defaultDBUser;
@Value("${spring.datasource.default.password}")
private String defaultDBPassword;
@Value("${spring.datasource.default.driverClassName}")
private String defaultDBDriverName;
@Value("${spring.datasource.default.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.default.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.default.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.default.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.default.filters}")
private String filters;
@Value("${spring.datasource.default.maxActive}")
private int maxActive;
@Bean
public DynamicDataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = DynamicDataSource.getInstance();
try {
DruidDataSource defaultDataSource = new DruidDataSource();
defaultDataSource.setUrl(defaultDBUrl);
defaultDataSource.setUsername(defaultDBUser);
defaultDataSource.setPassword(defaultDBPassword);
defaultDataSource.setDriverClassName(defaultDBDriverName);
defaultDataSource.setValidationQuery(validationQuery);
defaultDataSource.setMaxActive(maxActive);
defaultDataSource.setTestOnBorrow(testOnBorrow);
defaultDataSource.setTestOnReturn(testOnReturn);
defaultDataSource.setTestWhileIdle(testWhileIdle);
defaultDataSource.setFilters(filters);
Map<Object, Object> map = new HashMap<>();
map.put("default", defaultDataSource);
dynamicDataSource.setTargetDataSources(map);
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
} catch (Exception ex) {
ex.printStackTrace();
}
return dynamicDataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(
@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:mapper/*.xml"));
return bean.getObject();
}
@Bean(name = "sqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
这样在未切换数据源的情况下默认使用默认数据源
自定义数据源DataSource类:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.HashMap;
import java.util.Map;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static DynamicDataSource instance;
private static byte[] lock = new byte[0];
private static Map<Object, Object> dataSourceMap = new HashMap<>();
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
super.setTargetDataSources(targetDataSources);
dataSourceMap.putAll(targetDataSources);
super.afterPropertiesSet();// 必须添加该句,否则新添加数据源无法识别到
}
public Map<Object, Object> getDataSourceMap() {
return dataSourceMap;
}
public static synchronized DynamicDataSource getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new DynamicDataSource();
}
}
}
return instance;
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDBType();
}
}
通过ThreadLocal维护一个全局唯一的map来实现数据源的动态切换
public class DataSourceContextHolder {
private static final ThreadLocal<String> threadLocal = new ThreadLocal();
public static synchronized void setDBType(String data) {
threadLocal.set(data);
}
public static String getDBType() {
return threadLocal.get();
}
}
使用定时任务读取在默认数据库里设置好的其他数据库的信息
import com.alibaba.druid.pool.DruidDataSource;
import com..entity.DataSourceInfoEntity;
import com..service.DataSourceInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class InitTargetDataSources {
@Autowired
private DataSourceInfoService dataSourceInfoService;
/**
* 周期性的读取
*/
// @Scheduled(cron = "0 0/2 * * * ?")
public void readDataSourcePeriodically() {
setDataSourceInfo();
}
private void setDataSourceInfo() {
DataSourceContextHolder.setDBType("default");
List<DataSourceInfoEntity> list = dataSourceInfoService.getList();
//使用自己设置的sourceName作为数据源的key,使用这个进行切换
Map<Object, Object> dataSourceMap = list.stream().collect(Collectors.toMap(x -> x.getDatasourceName(), x -> {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(x.getDriverClassName());
druidDataSource.setUrl(x.getDatasourceUrl());
druidDataSource.setUsername(x.getDatasourceUsername());
druidDataSource.setPassword(x.getDatasourcePassword());
druidDataSource.setValidationQuery("SELECT 1 FROM DUAL");
druidDataSource.setKeepAlive(true);
return druidDataSource;
}));
DynamicDataSource dynamicDataSource = DynamicDataSource.getInstance();
Map<Object, Object> map = dynamicDataSource.getDataSourceMap();
map.putAll(dataSourceMap);
dynamicDataSource.setTargetDataSources(map);
dynamicDataSource.afterPropertiesSet();
}
}
public class DataSourceInfoEntity {
private int id;
private String datasourceName;
private String driverClassName;
private String datasourceUrl;
private String datasourceUsername;
private String datasourcePassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDatasourceName() {
return datasourceName;
}
public void setDatasourceName(String datasourceName) {
this.datasourceName = datasourceName;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getDatasourceUrl() {
return datasourceUrl;
}
public void setDatasourceUrl(String datasourceUrl) {
this.datasourceUrl = datasourceUrl;
}
public String getDatasourceUsername() {
return datasourceUsername;
}
public void setDatasourceUsername(String datasourceUsername) {
this.datasourceUsername = datasourceUsername;
}
public String getDatasourcePassword() {
return datasourcePassword;
}
public void setDatasourcePassword(String datasourcePassword) {
this.datasourcePassword = datasourcePassword;
}
}
@Service
public class DataSourceInfoServiceImpl implements DataSourceInfoService {
@Autowired
private DataSourceMapper dataSourceMapper;
@Override
public List<DataSourceInfoEntity> getList() {
DataSourceContextHolder.setDBType("default");
return dataSourceMapper.getList();
}
}
@Mapper
public interface DataSourceMapper {
@Select("SELECT * FROM datasource_info")
List<DataSourceInfoEntity> getList();
}
数据库结构
现在项目中已经存入了设定好的数据源
在数据库的操作前进行数据源的切换,就可以在不同的数据库中进行操作,比如从test1数据库查询数据后,再将数据插入到test2数据库中
DataSourceContextHolder.setDBType("test1");
List list=service.getList();
DataSourceContextHolder.setDBType("test2");
service.insert(list);
具体业务具体操作。大概就是这么用的,不过在数据库操作前一定要切换到对的数据源,不然可能会弄岔了
原博客,更多更详细:
https://blog.csdn.net/YHYR_YCY/article/details/78894940