Solo  当前访客:2 开始使用

多数据源动态切换


说明
AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
image.png
image.png

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=


0 0