spring boot jpa動態切換資料庫
阿新 • • 發佈:2018-12-25
專案上有兩個資料庫需要切換使用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<String> contextHolder = new ThreadLocal<String>(); /** * 校驗輸入的資料庫名稱是否正確 */ private static List<String> 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<Object, Object> 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");
}
}