spring boot jpa动态切换数据库

项目上有两个数据库需要切换使用jpa,查阅了网上的资料都是xml进行的配置,所以自己研究了稍加改动。
注:这里仅适用与1.5.x版本的spring boot 如果是2.0的请自行修改
1.配置数据库信息(application.properties):

spring.datasource.url:
spring.datasource.username:
spring.datasource.password:
spring.datasource.initialize=false   

spring.datasource.secondary.url=
spring.datasource.secondary.username=
spring.datasource.secondary.password=
spring.datasource.secondary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.driverClassName:com.mysql.jdbc.Driver
spring.jpa.database-platform:org.hibernate.dialect.MySQLDialect
spring.datasource.maxActive:200
spring.datasource.maxIdle:10
spring.datasource.initialSize:10
spring.datasource.testOnBorrow:true
spring.datasource.validationQuery:select 1
spring.datasource.autoReconnect:true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=false
spring.aop.auto=true

spring.datasource.secondary.maxActive=200
spring.datasource.secondary.maxIdle=10
spring.datasource.secondary.initialSize=10
spring.datasource.secondary.testOnBorrow=true
spring.datasource.secondary.validationQuery=select 1
spring.datasource.secondary.autoReconnect:true
spring.jpa.hibernate.secondary.ddl-auto=none
spring.jpa.secondary.show-sql=false
spring.aop.secondary.auto=true

2.创建存储数据源信息的类,并自定义实现AbstractRoutingDataSource

存储类:

public class DynamicDataSourceContextHolder {
    /**
     * 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal contextHolder = new ThreadLocal();
    /**
     * 校验输入的数据库名称是否正确
     */
    private static List dataSourceList=new ArrayList<>();

    /**
     * 使用setDataSourceType设置当前的
     * @param dataSourceType
     */
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get()==null?"primaryDataSource":contextHolder.get();
    }


    public static void clearDataSourceType() {
        contextHolder.remove();
    }

    public static void saveDataSourceTypeName(String name){
        dataSourceList.add(name);
    }

    public static boolean checkDataSourceType(String name){
        return dataSourceList.contains(name);
    }




}

3.加载数据库信息:

@Bean(name = "primaryDataSource")
    @Qualifier("primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource primaryDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @Qualifier("secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource(){
        return DataSourceBuilder.create().build();
    }

   @Bean(name="multipleDataSource")
    @Qualifier("multipleDataSource")
    @Primary
    public DataSource MultipleDataSourceToChoose(@Qualifier("primaryDataSource")DataSource dataSource,@Qualifier("secondaryDataSource")DataSource secondaryDataSource){
        DynamicDataSource dynamicDataSource=new DynamicDataSource();
        Map targetDataSources=new HashMap<>();
        targetDataSources.put("primaryDataSource",dataSource);
        targetDataSources.put("secondaryDataSource",secondaryDataSource);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(dataSource);
        DynamicDataSourceContextHolder.saveDataSourceTypeName("primaryDataSource");
        DynamicDataSourceContextHolder.saveDataSourceTypeName("secondaryDataSource");

        return dynamicDataSource;
    }

4.创建自定义注解并利用aop实现动态切换
自定义注解:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ChangDataSource {

    String name() default "primaryDataSource";
}

aop动态切换:

@Aspect
@Order(-10)//保证该AOP在@Transactional之前执行
@Component
public class DynamicDataSourceAspect {

    Logger logger= LoggerFactory.getLogger(DynamicDataSourceAspect.class);

   @Before(value = "@annotation(source)")
    public void changeDataSource(JoinPoint point,ChangDataSource source) throws Exception {
        String name=source.name();
        logger.info("change dataSource :"+name);
        if(!DynamicDataSourceContextHolder.checkDataSourceType(name)){
            throw new Exception("DataSource Not Exist,Please Check Your Annotation");
        }
        DynamicDataSourceContextHolder.setDataSourceType(name);

    }

    @AfterReturning(value = "@annotation(source)")
    public void restoreDataSource(JoinPoint point,ChangDataSource source) {
        //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。
        DynamicDataSourceContextHolder.clearDataSourceType();
        logger.info("clear change dataSource");
    }



}

你可能感兴趣的:(平时遇到的问题)