- 業務讀寫分離
- 業務分庫
- 業務功能模塊拆分多庫
- 按照數據源分別把mapper和entity放到不一樣的package下,而後用兩個數據源分別註冊、掃描對應的package,獨立的sessionfactoty
- 基於aop動態的切換的數據源
- DatabaseType列出全部的數據源的key---key
- DatabaseContextHolder是一個線程安全的DatabaseType容器,並提供了向其中設置和獲取DatabaseType的方法
- DynamicDataSource繼承AbstractRoutingDataSource並重寫其中的方法determineCurrentLookupKey(),在該方法中使用DatabaseContextHolder獲取當前線程的DatabaseType
- MyBatisConfig中生成2個數據源DataSource的bean---value
- MyBatisConfig中將1)和4)組成的key-value對寫入到DynamicDataSource動態數據源的targetDataSources屬性(固然,同時也會設置2個數據源其中的一個爲DynamicDataSource的defaultTargetDataSource屬性中)
- 將DynamicDataSource做爲primary數據源注入到SqlSessionFactory的dataSource屬性中去,而且該dataSource做爲transactionManager的入參來構造DataSourceTransactionManager
- 使用的時候,在dao層或service層先使用DatabaseContextHolder設置將要使用的數據源key,而後再調用mapper層進行相應的操做,建議放在dao層去作(固然也能夠使用spring aop+自定註解去作)
- 注意:在mapper層進行操做的時候,會先調用determineCurrentLookupKey()方法獲取一個數據源(獲取數據源:先根據設置去targetDataSources中去找,若沒有,則選擇defaultTargetDataSource),以後在進行數據庫操做。
spring.aop.proxy-target-class = true spring.aop.auto = true spring.datasource.druid.db1.url = spring.datasource.druid.db1.username = spring.datasource.druid.db1.password = spring.datasource.druid.db1.driver-class-name = com.mysql.jdbc.Driver spring.datasource.druid.db1.initialSize = 5 spring.datasource.druid.db1.minIdle = 5 spring.datasource.druid.db1.maxActive = 20 spring.datasource.druid.db2.url = spring.datasource.druid.db2.username = spring.datasource.druid.db2.password = spring.datasource.druid.db2.driver-class-name = com.mysql.jdbc.Driver spring.datasource.druid.db2.initialSize = 5 spring.datasource.druid.db2.minIdle = 5 spring.datasource.druid.db2.maxActive = 20 spring.datasource.druid.db3.url = spring.datasource.druid.db3.username = spring.datasource.druid.db3.password = spring.datasource.druid.db3.driver-class-name = com.mysql.jdbc.Driver spring.datasource.druid.db3.initialSize = 5 spring.datasource.druid.db3.minIdle = 5 spring.datasource.druid.db3.maxActive = 20
@Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.druid.db1") public DataSource db1() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.druid.db2") public DataSource db2() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db3") @ConfigurationProperties(prefix = "spring.datasource.druid.db3") public DataSource db3() { return DruidDataSourceBuilder.create().build(); }
@Getter @AllArgsConstructor public enum DBTypeEnum { db1("db1"), db2("db2"), db3("db3"); private String value; }
/** * 動態數據源配置 * * @return */ @Bean @Primary public DataSource multipleDataSource( @Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2, @Qualifier("db3") DataSource db3) { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DBTypeEnum.db1.getValue(), db1); targetDataSources.put(DBTypeEnum.db2.getValue(), db2); targetDataSources.put(DBTypeEnum.db3.getValue(), db3); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(db2); return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2(), db3())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); // PerformanceInterceptor(),OptimisticLockerInterceptor() // 添加分頁功能 sqlSessionFactory.setPlugins(new Interceptor[] {paginationInterceptor()}); sqlSessionFactory.setGlobalConfig(globalConfiguration()); return sqlSessionFactory.getObject(); }
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDbType(); } }
public class DbContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal<>(); /** * 設置數據源 * * @param dbTypeEnum */ public static void setDbType(DBTypeEnum dbTypeEnum) { contextHolder.set(dbTypeEnum.getValue()); } /** * 取得當前數據源 * * @return */ public static String getDbType() { return (String) contextHolder.get(); } /** 清除上下文數據 */ public static void clearDbType() { contextHolder.remove(); } }
@Component @Order(value = -100) @Slf4j @Aspect public class DataSourceSwitchAspect { @Pointcut("execution(* top.zhuofan.datafly.mapper.db1..*.*(..))") private void db1Aspect() {} @Pointcut("execution(* top.zhuofan.datafly.mapper.db2..*.*(..))") private void db2Aspect() {} @Pointcut("execution(* top.zhuofan.datafly.mapper.db3..*.*(..))") private void db3Aspect() {} @Before("db1Aspect()") public void db1() { log.debug("切換到db1 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db1); } @Before("db2Aspect()") public void db2() { log.debug("切換到db2 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db2); } @Before("db3Aspect()") public void db3() { log.debug("切換到db3 數據源..."); DbContextHolder.setDbType(DBTypeEnum.db3); } }
更多精彩,敬請關注, 程序員導航網 https://chenzhuofan.topmysql