springboot 多数据源 读写分离 AOP方式
大家好,我是烤鴨:
? ? ? ? 今天分享springboot讀寫分離配置。
? ? ? ? ?環境:
? ? ? ? ? ? ? ? ?springboot ?2.1.0.RELEASE
? ? ? ? ?場景說明,目前的需求是 讀數據源 * 2 + 寫數據源 * 1
?
1.? ? 配置文件
?? ?application.yml
2.? ? 配置類
?DataSourceConfig.java
?默認 讀數據源,如果需要增加或者減少數據源需要修改 myRoutingDataSource 方法中的參數
package com.test.test.config.db;import com.test.test.datasource.MyRoutingDataSource; import com.test.test.datasource.enums.DBTypeEnum; import com.zaxxer.hikari.HikariDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment;import javax.sql.DataSource; import java.util.HashMap; import java.util.Map;/*** 關于數據源配置,參考SpringBoot官方文檔第79章《Data Access》* 79. Data Access* 79.1 Configure a Custom DbSource* 79.2 Configure Two DataSources*/@Configuration public class DataSourceConfig {@AutowiredEnvironment environment;@Bean@ConfigurationProperties("spring.datasource.readaw")public DataSource readDataSourceAw() {DataSource build = DataSourceBuilder.create().build();HikariDataSource hikariDataSource = buildDataSource(build,"readaw");return hikariDataSource;}@Bean@ConfigurationProperties("spring.datasource.readdc")public DataSource readDataSourceDc() {DataSource build = DataSourceBuilder.create().build();HikariDataSource hikariDataSource = buildDataSource(build,"readdc");return hikariDataSource;}@Bean@ConfigurationProperties("spring.datasource.write")public DataSource writeDataSource() {DataSource build = DataSourceBuilder.create().build();HikariDataSource hikariDataSource = buildDataSource(build,"write");return hikariDataSource;}@Beanpublic DataSource myRoutingDataSource(@Qualifier("readDataSourceAw") DataSource readDataSourceAw,@Qualifier("readDataSourceDc") DataSource readDataSourceDc,@Qualifier("writeDataSource") DataSource writeDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DBTypeEnum.READ_AW, readDataSourceAw);targetDataSources.put(DBTypeEnum.READ_DC, readDataSourceDc);targetDataSources.put(DBTypeEnum.WRITE, writeDataSource);MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();myRoutingDataSource.setDefaultTargetDataSource(readDataSourceAw);myRoutingDataSource.setTargetDataSources(targetDataSources);return myRoutingDataSource;}public HikariDataSource buildDataSource(DataSource dataSource,String dataSourcePrefix){HikariDataSource hikariDataSource= (HikariDataSource) dataSource;hikariDataSource.setDriverClassName(environment.getProperty("spring.datasource."+dataSourcePrefix+".driver-class-name"));hikariDataSource.setJdbcUrl(environment.getProperty("spring.datasource."+dataSourcePrefix+".jdbc-url"));hikariDataSource.setUsername(environment.getProperty("spring.datasource."+dataSourcePrefix+".username"));hikariDataSource.setPassword(environment.getProperty("spring.datasource."+dataSourcePrefix+".password"));hikariDataSource.setMinimumIdle(Integer.parseInt(environment.getProperty("spring.datasource."+dataSourcePrefix+".minIdle")));hikariDataSource.setConnectionTimeout(Long.parseLong(environment.getProperty("spring.datasource."+dataSourcePrefix+".connectionTimeout")));hikariDataSource.setValidationTimeout(Long.parseLong(environment.getProperty("spring.datasource."+dataSourcePrefix+".validationTimeout")));hikariDataSource.setMaximumPoolSize(Integer.parseInt(environment.getProperty("spring.datasource."+dataSourcePrefix+".maxPoolSize")));return hikariDataSource;} }MyBatisConfig.java
注意映射mapper文件路徑是在這里修改的,因為重新注入了sqlSession, yml中配置的無效
package com.test.test.config.mybatis;import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.annotation.Resource; import javax.sql.DataSource;@EnableTransactionManagement @Configuration public class MyBatisConfig {@Resource(name = "myRoutingDataSource")private DataSource myRoutingDataSource;@Beanpublic SqlSessionFactory sqlSessionFactory() throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(myRoutingDataSource);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/**/*.xml"));return sqlSessionFactoryBean.getObject();}@Beanpublic PlatformTransactionManager platformTransactionManager() {return new DataSourceTransactionManager(myRoutingDataSource);} }DataSourceAop.java
aop配置類,通過aop的方式限制哪個service的方法連接哪個數據源
目前是根據類上的注解來判斷,可以修改為根據方法的注解來判斷走哪個數據源
DBTypeEnum.java
數據源枚舉,增加和減少數據源修改即可
public enum DBTypeEnum {READ_AW, READ_DC, WRITE;}DBContextHolder.java
數據源切換類,保持當前線程綁定哪個數據源
package com.test.test.datasource.handler;import com.test.test.datasource.enums.DBTypeEnum; import org.apache.commons.lang3.StringUtils;import java.util.concurrent.atomic.AtomicInteger; /*** @Author gmwang* @Description // 數據源切換類* @Date 2019/4/30 9:20* @Param* @return**/ public class DBContextHolder {private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();private static final AtomicInteger counter = new AtomicInteger(-1);public static void set(DBTypeEnum dbType) {contextHolder.set(dbType);}public static DBTypeEnum get() {return contextHolder.get();}public static void read(String value) {if(StringUtils.isBlank(value)){set(DBTypeEnum.READ_AW);System.out.println("切換到讀"+DBTypeEnum.READ_AW.toString());}if (DBTypeEnum.READ_DC.toString().equals(value)){set(DBTypeEnum.READ_DC);System.out.println("切換到讀"+DBTypeEnum.READ_DC.toString());}}public static void write() {set(DBTypeEnum.WRITE);System.out.println("切換到寫"+DBTypeEnum.WRITE.toString());} }MyRoutingDataSource.java
多數據源的路由類
package com.test.test.datasource;import com.test.test.datasource.handler.DBContextHolder; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.lang.Nullable; /*** @Author gmwang* @Description //多數據源的路由* @Date 2019/4/30 9:38* @Param* @return**/ public class MyRoutingDataSource extends AbstractRoutingDataSource {/*** @Author gmwang* @Description //根據Key獲取數據源的信息,上層抽象函數的鉤子* @Date 2019/4/30 9:39* @Param []* @return java.lang.Object**/@Nullable@Overrideprotected Object determineCurrentLookupKey() {return DBContextHolder.get();} }DbSource
數據源注解,加在serivice實現類上,指定 value,AOP根據注解獲取指定的數據源。
package com.test.test.datasource.annotation;import java.lang.annotation.*;@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface DbSource {String value(); }例如本例中,默認讀庫是? READ_AW ,如果不加注解默認,讀取默認庫。如果指定注解 READ_DC,就用指定的數據源。
?
3.? ? 結果測試
偽代碼:
?
在tes方法中使用查詢(不同的庫)后插入操作,結果如圖所示。
?
總結
以上是生活随笔為你收集整理的springboot 多数据源 读写分离 AOP方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hadoop部分架构图
- 下一篇: iOS开发tableview二级联动的细