- 业务读写分离
- 业务分库
- 业务功能模块拆分多库
- 按照数据源分别把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