1.yml多数据源配置

amdb,josdb,josdbqy,分别为自定义数据源名称,type指定数据源使用的连接池。

2.新建类DataSourceProperties用于读取yml文件中的自定义数据源属性

@Component
public class DataSourceProperties {
    @Value("${spring.datasource.amdb.jdbc-url}")
    private String amdbUrl;
    @Value("${spring.datasource.amdb.username}")
    private String amdbUserName;
    @Value("${spring.datasource.amdb.password}")
    private String amdbPassword;
    @Value("${spring.datasource.amdb.driver-class-name}")
    private String amdbDriverClass;

    @Value("${spring.datasource.josdb.jdbc-url}")
    private String josdbUrl;
    @Value("${spring.datasource.josdb.username}")
    private String josdbUserName;
    @Value("${spring.datasource.josdb.password}")
    private String josdbPassword;
    @Value("${spring.datasource.josdb.driver-class-name}")
    private String josdbDriverClass;


    @Value("${spring.datasource.josdbqy.jdbc-url}")
    private String josdbqyUrl;
    @Value("${spring.datasource.josdbqy.username}")
    private String josdbqyUserName;
    @Value("${spring.datasource.josdbqy.password}")
    private String josdbqyPassword;
    @Value("${spring.datasource.josdbqy.driver-class-name}")
    private String josdbqyDriverClass;

    public String getAmdbUrl() {
        return amdbUrl;
    }

    public void setAmdbUrl(String amdbUrl) {
        this.amdbUrl = amdbUrl;
    }

    public String getAmdbUserName() {
        return amdbUserName;
    }

    public void setAmdbUserName(String amdbUserName) {
        this.amdbUserName = amdbUserName;
    }

    public String getAmdbPassword() {
        return amdbPassword;
    }

    public void setAmdbPassword(String amdbPassword) {
        this.amdbPassword = amdbPassword;
    }

    public String getAmdbDriverClass() {
        return amdbDriverClass;
    }

    public void setAmdbDriverClass(String amdbDriverClass) {
        this.amdbDriverClass = amdbDriverClass;
    }

    public String getJosdbUrl() {
        return josdbUrl;
    }

    public void setJosdbUrl(String josdbUrl) {
        this.josdbUrl = josdbUrl;
    }

    public String getJosdbUserName() {
        return josdbUserName;
    }

    public void setJosdbUserName(String josdbUserName) {
        this.josdbUserName = josdbUserName;
    }

    public String getJosdbPassword() {
        return josdbPassword;
    }

    public void setJosdbPassword(String josdbPassword) {
        this.josdbPassword = josdbPassword;
    }

    public String getJosdbDriverClass() {
        return josdbDriverClass;
    }

    public void setJosdbDriverClass(String josdbDriverClass) {
        this.josdbDriverClass = josdbDriverClass;
    }

    public String getJosdbqyUrl() {
        return josdbqyUrl;
    }

    public void setJosdbqyUrl(String josdbqyUrl) {
        this.josdbqyUrl = josdbqyUrl;
    }

    public String getJosdbqyUserName() {
        return josdbqyUserName;
    }

    public void setJosdbqyUserName(String josdbqyUserName) {
        this.josdbqyUserName = josdbqyUserName;
    }

    public String getJosdbqyPassword() {
        return josdbqyPassword;
    }

    public void setJosdbqyPassword(String josdbqyPassword) {
        this.josdbqyPassword = josdbqyPassword;
    }

    public String getJosdbqyDriverClass() {
        return josdbqyDriverClass;
    }

    public void setJosdbqyDriverClass(String josdbqyDriverClass) {
        this.josdbqyDriverClass = josdbqyDriverClass;
    }
}

3.创建类DynamicDataSource继承AbstractRoutingDataSource并实determineCurrentLookupKey()

方法,从DataSourceContextHolder动态获取对应线程的数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceContextHolder.getDataSource();
	}

}

 

4.再创建DataSourceConfig类,创建数据源


@Configuration
public class DataSourceConfig {

    @Autowired
    DataSourceProperties dataSourceProperties;

    @Bean(name = "amdb")
    public DataSource amdb() {
        HikariDataSource amdb = new HikariDataSource();
        amdb.setJdbcUrl(dataSourceProperties.getAmdbUrl());
        amdb.setDriverClassName(dataSourceProperties.getAmdbDriverClass());
        amdb.setUsername(dataSourceProperties.getAmdbUserName());
        amdb.setPassword(dataSourceProperties.getAmdbPassword());
        amdb.setPoolName("HikariPool-amdb");
        amdb.setAutoCommit(true);
        amdb.setReadOnly(false);
        amdb.setConnectionTestQuery("SELECT 1;");
        return amdb;
    }

    @Bean(name = "josdb")
    public DataSource josdb() {
        HikariDataSource josdb = new HikariDataSource();
        josdb.setJdbcUrl(dataSourceProperties.getJosdbUrl());
        josdb.setDriverClassName(dataSourceProperties.getJosdbDriverClass());
        josdb.setUsername(dataSourceProperties.getJosdbUserName());
        josdb.setPassword(dataSourceProperties.getJosdbPassword());
        josdb.setPoolName("HikariPool-josdb");
        josdb.setAutoCommit(true);
        josdb.setReadOnly(false);
        josdb.setConnectionTestQuery("SELECT 1;");
        return josdb;
    }

    @Bean(name = "josdbqy")
    public DataSource josdbqy() {
        HikariDataSource josdbqy = new HikariDataSource();
        josdbqy.setJdbcUrl(dataSourceProperties.getJosdbqyUrl());
        josdbqy.setDriverClassName(dataSourceProperties.getJosdbqyDriverClass());
        josdbqy.setUsername(dataSourceProperties.getJosdbqyUserName());
        josdbqy.setPassword(dataSourceProperties.getJosdbqyPassword());
        josdbqy.setPoolName("HikariPool-josdbqy");
        josdbqy.setAutoCommit(true);
        josdbqy.setReadOnly(false);
        josdbqy.setConnectionTestQuery("SELECT 1;");
        return josdbqy;
    }

    @Bean(name = "amdbJdbcTemplate")
    public JdbcTemplate amdbJdbcTemplate(
            @Qualifier("amdb") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "josdbJdbcTemplate")
    public JdbcTemplate josdbJdbcTemplate(
            @Qualifier("josdb") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "josdbqyJdbcTemplate")
    public JdbcTemplate josdbqyJdbcTemplate(
            @Qualifier("josdbqy") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Primary
    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>(3);
        targetDataSources.put(DataSourceTypeEnum.amdb, amdb());
        targetDataSources.put(DataSourceTypeEnum.josdb, josdb());
        targetDataSources.put(DataSourceTypeEnum.josdbqy, josdbqy());
        // 添加数据源名称到列表
        DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.amdb.name());
        DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.josdb.name());
        DataSourceContextHolder.dataSourceIds.add(DataSourceTypeEnum.josdbqy.name());
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 如果没有指定数据源自动切换主数据源
        dynamicDataSource.setDefaultTargetDataSource(amdb());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }


    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
        jpaTransactionManager.setDataSource(dynamicDataSource());
        return jpaTransactionManager;
    }

创建对应的三个数据源,amdb,josdb,josdbqy,再创建对应的jdbctemplate, 再创建指定数据源的方法dynamicDataSource(),以及最后指定对应的Jpa事务管理器。

5.创建DataSourceContextHolder动态数据源上下文管理

public class DataSourceContextHolder {
	// 存放当前线程使用的数据源类型
	private static final ThreadLocal<DataSourceTypeEnum> contextHolder = new ThreadLocal<>();

	 //存放数据源id
    public static List<String> dataSourceIds = new ArrayList<String>();


	// 设置数据源
	public static void setDataSource(DataSourceTypeEnum type) {
		contextHolder.set(type);
	}

	// 获取数据源
	public static DataSourceTypeEnum getDataSource() {
		return contextHolder.get();
	}

	// 清除数据源
	public static void clearDataSource() {
		contextHolder.remove();
	}

	//判断当前数据源是否存在
    public static boolean isContainsDataSource(String dataSourceId) {
        return dataSourceIds.contains(dataSourceId);
    }
}

6.创建自定义注解DS类

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface DS {
	DataSourceTypeEnum value() default DataSourceTypeEnum.amdb;
}

7.使用aop的切面来切换数据源。

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

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    @Before(value = "@annotation(source)")
    public void changeDataSource(JoinPoint point, DS source) throws Exception {
        DataSourceTypeEnum currentSource = source.value();
        logger.info("Change DataSource To:[" + currentSource + "]");
        DataSourceContextHolder.setDataSource(currentSource);
    }

    @After(value = "@annotation(source)")
    public void restoreDataSource(JoinPoint point, DS source) {
        // 方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。
        DataSourceContextHolder.clearDataSource();
        logger.info("Clear Change DataSource...");
    }

}

8.在service的实现类来使用数据源的切换,在所需方法上加上DS注解以及对应的数据源类型,即可实现数据源切换

 9.加上枚举类

public enum DataSourceTypeEnum {
	amdb, josdb, josdbqy
}

 

 

 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐