多数据源动态切换
说明
AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
MyBatisConfig
package com.demo.datasources.configuration;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* springboot集成mybatis的基本入口 1)创建数据源(如果采用的是默认的tomcat-jdbc数据源,则不需要)
* 2)创建SqlSessionFactory 3)配置事务管理器,除非需要使用事务,否则不用配置
*/
@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.demo.aicCase.mapper")
public class MyBatisConfig {
@Autowired
private Environment env;
private static DynamicDataSource dataSource;
private static Map<String, DataSource> dataSourceMap = new HashMap<String, DataSource>();
static {
if (dataSource == null) dataSource = new DynamicDataSource();
}
@Bean
public DataSource dataMZbackupDataSource() throws Exception {
Properties props = new Properties();
props.put("url", this.env.getProperty("data.mzbackup.datasource.url"));
props.put("username", this.env.getProperty("data.mzbackup.datasource.username"));
props.put("password", this.env.getProperty("data.mzbackup.datasource.password"));
this.commonSettings(props);
final DataSource mz = DruidDataSourceFactory.createDataSource(props);
dataSourceMap.put("mz", mz);
return mz;
}
@Bean
public DataSource dataGDdjzrDataSource() throws Exception {
Properties props = new Properties();
props.put("url", this.env.getProperty("data.gddjzr.datasource.url"));
props.put("username", this.env.getProperty("data.gddjzr.datasource.username"));
props.put("password", this.env.getProperty("data.gddjzr.datasource.password"));
this.commonSettings(props);
final DataSource gd = DruidDataSourceFactory.createDataSource(props);
dataSourceMap.put("gd", gd);
return gd;
}
private void commonSettings(Properties props) {
props.put("driverClassName", this.env.getProperty("common.datasource.driver-class-name"));
props.put("filters", this.env.getProperty("common.datasource.filters"));
props.put("initialSize", this.env.getProperty("common.datasource.initialSize"));
props.put("maxActive", this.env.getProperty("common.datasource.maxActive"));
props.put("maxWait", this.env.getProperty("common.datasource.maxWait"));
props.put("timeBetweenEvictionRunsMillis", this.env.getProperty("common.datasource.timeBetweenEvictionRunsMillis"));
props.put("minEvictableIdleTimeMillis", this.env.getProperty("common.datasource.minEvictableIdleTimeMillis"));
props.put("validationQuery", this.env.getProperty("common.datasource.validationQuery"));
props.put("testWhileIdle", this.env.getProperty("common.datasource.testWhileIdle"));
props.put("testOnBorrow", this.env.getProperty("common.datasource.testOnBorrow"));
props.put("testOnReturn", this.env.getProperty("common.datasource.testOnReturn"));
props.put("poolPreparedStatements", this.env.getProperty("common.datasource.poolPreparedStatements"));
props.put("maxPoolPreparedStatementPerConnectionSize", this.env.getProperty("common.datasource.maxPoolPreparedStatementPerConnectionSize"));
}
@Bean
@Primary
public DynamicDataSource dataSource(@Qualifier("dataGDdjzrDataSource") DataSource dataGDbackupDataSource, @Qualifier("dataMZbackupDataSource") DataSource dataMZbackupDataSource) {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
targetDataSources.put(DatabaseType.mzrongzaibackup, dataMZbackupDataSource);
targetDataSources.put(DatabaseType.gdrongzaibackup, dataGDbackupDataSource);
dataSource.setTargetDataSources((Map) targetDataSources);
dataSource.setDefaultTargetDataSource((Object) dataGDbackupDataSource);
return dataSource;
}
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
fb.setDataSource((DataSource) dataSource);
return fb.getObject();
}
@Bean
public DataSourceTransactionManager transactionManager() throws Exception {
return new DataSourceTransactionManager((DataSource) dataSource);
}
}
DatabaseType容器
package com.demo.datasources.configuration;
/**
* 作用:
* 1、保存一个线程安全的DatabaseType容器
*/
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
public static void setDatabaseType(DatabaseType type){
contextHolder.set(type);
}
public static DatabaseType getDatabaseType(){
return contextHolder.get();
}
}
数据源key
package com.demo.datasources.configuration;
/**
* 列出所有的数据源key(常用数据库名称来命名)
* 注意:
* 1)这里数据源与数据库是一对一的
* 2)DatabaseType中的变量名称就是数据库的名称
*/
public enum DatabaseType {
mzrongzaibackup,
gdrongzaibackup
}
继承AbstractRoutingDataSource
package com.demo.datasources.configuration;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class DynamicDataSource extends AbstractRoutingDataSource
{
static ThreadLocal<Long> connectTime;
static {
DynamicDataSource.connectTime = new ThreadLocal<Long>();
}
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
public Connection getConnection() throws SQLException {
final long start = System.currentTimeMillis();
final Connection conn = super.getConnection();
DynamicDataSource.connectTime.set(System.currentTimeMillis() - start);
return conn;
}
public static long getConnectTime() {
return DynamicDataSource.connectTime.get();
}
}
使用
//通过传入key获取不同数据源
//DatabaseContextHolder.setDatabaseType(DatabaseType.gddjzr);
DatabaseContextHolder.setDatabaseType(DatabaseType.mzrongzaibackup);
Map<String, String> byOpenIds = creditMapper.findByOpenIds();
配置:
common.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
common.datasource.filters=stat
common.datasource.initialSize=2
common.datasource.maxActive=600
common.datasource.maxWait=60000
common.datasource.timeBetweenEvictionRunsMillis=60000
common.datasource.minEvictableIdleTimeMillis=300000
common.datasource.validationQuery=SELECT 1
common.datasource.testWhileIdle=true
common.datasource.testOnBorrow=false
common.datasource.testOnReturn=false
common.datasource.poolPreparedStatements=false
common.datasource.maxPoolPreparedStatementPerConnectionSize=200
system.datasource.username=
system.datasource.password=
system.datasource.url=