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

相關文章
相關標籤/搜索