mybatis plus + AOP 多数据源自动切换
1. 数据库配置
# .yml 文件 spring: datasource: db1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc-url # 配置 username: root password: psw db2: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc-url # 配置 username: root password: psw
2. 数据源枚举类
public enum DataSourceEnums { PRIMARY("primaryDataSource"), SECOND("secondDataSource"); private String value; DataSourceEnums(String value){this.value=value;} public String getValue() { return value; } }
3. mybatis plus Config 数据源切换类
@Configuration @MapperScan(value = {"com.example.demo.dao"}) public class MybatisPlusConfig { @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.db1") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondDataSource") @ConfigurationProperties(prefix = "spring.datasource.db2") public DataSource secondDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "multipleTransactionManager") @Primary public DataSourceTransactionManager multipleTransactionManager(@Qualifier("multipleDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } /** * 动态数据源配置 */ @Bean(name = "multipleDataSource") @Primary public DataSource multipleDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("secondDataSource") DataSource secondDataSource) { DataSourceContextHolder dynamicDataSource = new DataSourceContextHolder(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceEnums.PRIMARY.getValue(), primaryDataSource); targetDataSources.put(DataSourceEnums.SECOND.getValue(), secondDataSource); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(secondDataSource); // 程序默认数据源,这个要根据程序调用数据源频次,经常把常调用的数据源作为默认 return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(primaryDataSource(), secondDataSource())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); //是否使用转驼峰 configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration);//扫描 mapper 路径 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resource = resolver.getResources("classpath:mapper/**/*.xml"); sqlSessionFactory.setMapperLocations(resource); return sqlSessionFactory.getObject(); } }
3. DataSource 数据源获取类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; @Slf4j public class DataSourceContextHolder extends AbstractRoutingDataSource { public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); /** * 获取数据源 */ @Override protected Object determineCurrentLookupKey() { log.info("当前选择的数据源是:" + contextHolder.get()); return contextHolder.get(); } /** * 设置数据源*/ public static void setDataSource(String db){ contextHolder.set(db); } /** * 取得当前数据源 * @return */ public static String getDataSource(){ return contextHolder.get(); } /** * 清除上下文数据 */ public static void clear(){ contextHolder.remove(); } }
4. AOP切面
import com.example.demo.config.DataSourceContextHolder; import com.example.demo.enums.DataSourceEnums; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(-100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高 @Slf4j public class AOP { /** * mybatis plus 动态切换数据源 * */ // 定义切点 @Before("execution(* com.example.demo.dao.db1..*(..))") public void db1() { log.info("数据源切换到db1..."); DataSourceContextHolder.setDataSource(DataSourceEnums.PRIMARY.getValue()); } @Before("execution(* com.example.demo.dao.db2..*(..))") public void db2() { log.info("数据源切换到db2..."); DataSourceContextHolder.setDataSource(DataSourceEnums.SECOND.getValue()); } }