配置文件: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