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
创建对应的三个数据源,amdb,josdb,josdbqy,再创建对应的jdbctemplate, 再创建指定数据源的方法dynamicDataSource(),以及最后指定对应的Jpa事务管理器。
5.创建DataSourceContextHolder动态数据源上下文管理
public class DataSourceContextHolder {
// 存放当前线程使用的数据源类型
private static final ThreadLocal contextHolder = new ThreadLocal<>();
//存放数据源id
public static List dataSourceIds = new ArrayList();
// 设置数据源
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
}