SpringBoot+MyBatis多数据源切换

配置文件:mysql

datasource:
  master:
    url: jdbc:mysql://ip/db?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
  slave:
    url: jdbc:mysql://ip/db?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

配置数据源:sql

@Configuration
public class DataSourceConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceConfiguration.class);

    @Value("${datasource.master.url}")
    private String masterUrl;
    @Value("${datasource.master.username}")
    private String masterUserName;
    @Value("${datasource.master.password}")
    private String masterPassword;

    @Value("${datasource.slave.url}")
    private String slaveUrl;
    @Value("${datasource.slave.username}")
    private String slaveUserName;
    @Value("${datasource.slave.password}")
    private String slavePassword;

    @Bean("masterDataSource")
    @Primary
    public DataSource masterDataSource() {
        logger.info("-------------------- masterDataSource init ---------------------");
        DataSource dataSource = getDataSource(masterUrl, masterUserName, masterPassword);
        return dataSource;
    }

    @Bean("slaveDataSource")
    public DataSource slaveDataSource(){
        logger.info("-------------------- slaveDataSource init ---------------------");
        DataSource dataSource = getDataSource(slaveUrl, slaveUserName, slavePassword);
        return dataSource;
    }

    private DataSource getDataSource(String url, String userName, String password) {
        logger.info("datasource 开始注入...");
        org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl(url);
        dataSource.setUsername(userName);
        dataSource.setPassword(password);

        logger.info("datasource url: {}", url);
        logger.info("datasource 注入完成");
        return dataSource;
    }
}

配置SqlSessionFactory:apache

@Configuration
@AutoConfigureAfter(DataSourceConfiguration.class)
public class MybatisConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(MybatisConfiguration.class);

    @Autowired
    @Qualifier("masterDataSource")
    private DataSource masterDataSource;
    @Autowired
    @Qualifier("slaveDataSource")
    private DataSource slaveDataSource;

    @Bean(name="sqlSessionFactory")
    public SqlSessionFactory sessionFactory() throws Exception {
        logger.info("--------------------  sqlSessionFactory init ---------------------");
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(roundRobinDataSourceProxy());
        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name="roundRobinDataSourceProxy")
    public AbstractRoutingDataSource roundRobinDataSourceProxy() {
        Map<Object, Object> targetDataSources = new HashMap();
        targetDataSources.put(DatabaseType.master.getType(), masterDataSource);
        targetDataSources.put(DatabaseType.slave.getType(), slaveDataSource);

        AbstractRoutingDataSource routingDataSource = new DynamicDataSource();
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        return routingDataSource;
    }
}

创建主从枚举:tomcat

public enum  DatabaseType {
    slave("slave", "从库"), master("master", "主库");
    DatabaseType(String type, String name) {
        this.type = type;
        this.name = name;
    }

    private String type;
    private String name;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

经过ThreadLocal切换主从数据源:session

public class DatabaseContextHolder {
    private static final Logger logger = LoggerFactory.getLogger(DatabaseContextHolder.class);

    private static final ThreadLocal<String> local = new ThreadLocal<String>();

    public static ThreadLocal<String> getLocal() {
        return local;
    }

    public static void slave() {
        local.set(DatabaseType.slave.getType());
    }

    public static void master(){
        local.set(DatabaseType.master.getType());
    }

    public static String getJdbcType(){
        return local.get();
    }
}

配置数据源主从切换:app

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        String typeKey = DatabaseContextHolder.getJdbcType();
        if (typeKey.equals(DatabaseType.master.getType()))
            return DatabaseType.master.getType();
        else
            return DatabaseType.slave.getType();
    }
}

经过AOP拦截DAO方法进行主从切换:ide

@Aspect
@Component
public class DataSourceAop {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceAop.class);

    @Before("execution(* com.xxx.mapper..*.get*(..)) || execution(* com.xxx.mapper..*.find*(..))")
    public void setReadDataSourceType() {
        DatabaseContextHolder.master();
        logger.info("dataSource切换到:slave");
    }

    @Before("execution(* com.xxx.mapper..*.insert*(..)) || execution(* com.xxx.mapper..*.update*(..))")
    public void setWriteDataSourceType() {
        DatabaseContextHolder.master();
        logger.info("dataSource切换到:master");
    }
}

完成this

相关文章
相关标签/搜索