成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot讀寫分離組件開發詳解

開發 前端
本篇詳細介紹關于SpringBoot讀寫分離組件開發的相關內容,一寫多讀,讀可以任意配置多個,默認都是從寫庫中進行操作,只有符合條件的方法(指定的目標方法或者標有指定注解的方法才會從讀庫中操作)。獨立打成一個jar包放入本地倉庫。

[[389704]]

環境:springboot2.2.6RELEASE

實現目標:一寫多讀,讀可以任意配置多個,默認都是從寫庫中進行操作,只有符合條件的方法(指定的目標方法或者標有指定注解的方法才會從讀庫中操作)。獨立打成一個jar包放入本地倉庫。

實現原理:通過aop。

1.pom.xml配置文件

  1. <dependency> 
  2.             <groupId>org.springframework.boot</groupId> 
  3.             <artifactId>spring-boot-starter</artifactId> 
  4. </dependency> 
  5. <dependency> 
  6.             <groupId>org.springframework.boot</groupId> 
  7.             <artifactId>spring-boot-starter-data-jpa</artifactId> 
  8. </dependency> 
  9. <dependency> 
  10.             <groupId>org.springframework.boot</groupId> 
  11.             <artifactId>spring-boot-configuration-processor</artifactId> 
  12.             <optional>true</optional> 
  13. </dependency> 

 2.application.yml配置文件

  1. pack: 
  2.   datasource: 
  3.     pointcut: execution(public * net.greatsoft.service.base.*.*(..)) || execution(public * net.greatsoft.service.xxx.*.*(..)) 
  4.     master: 
  5.       driverClassName: oracle.jdbc.driver.OracleDriver 
  6.       jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl 
  7.       username: test 
  8.       password: test 
  9.       minimumIdle: 10 
  10.       maximumPoolSize: 200 
  11.       autoCommit: true 
  12.       idleTimeout: 30000 
  13.       poolName: MbookHikariCP 
  14.       maxLifetime: 1800000 
  15.       connectionTimeout: 30000 
  16.       connectionTestQuery: SELECT 1 FROM DUAL   
  17.     slaves: 
  18.       - driverClassName: oracle.jdbc.driver.OracleDriver 
  19.         jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl 
  20.         username: dc 
  21.         password: dc 
  22.         minimumIdle: 10 
  23.         maximumPoolSize: 200 
  24.         autoCommit: true 
  25.         idleTimeout: 30000 
  26.         poolName: MbookHikariCP 
  27.         maxLifetime: 1800000 
  28.         connectionTimeout: 30000 
  29.         connectionTestQuery: SELECT 1 FROM DUAL 
  30.       - driverClassName: oracle.jdbc.driver.OracleDriver 
  31.         jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl 
  32.         username: empi 
  33.         password: empi 
  34.         minimumIdle: 10 
  35.         maximumPoolSize: 200 
  36.         autoCommit: true 
  37.         idleTimeout: 30000 
  38.         poolName: MbookHikariCP 
  39.         maxLifetime: 1800000 
  40.         connectionTimeout: 30000 
  41.         connectionTestQuery: SELECT 1 FROM DUAL 

 pointcut:定義切點,那些方法是需要攔截(從讀庫中操作)。

master:寫庫配置。

slaves:讀庫配置(List集合)。

3.屬性配置類

  1. @Component 
  2. @ConfigurationProperties(prefix = "pack.datasource"
  3. public class RWDataSourceProperties { 
  4.      
  5.     private String pointcut ; 
  6.     private HikariConfig master ; 
  7.     private List<HikariConfig> slaves = new ArrayList<>(); 
  8.      

 4.讀寫配置類

  1. public class RWConfig  { 
  2.      
  3.     private static Logger logger = LoggerFactory.getLogger(RWConfig.class) ; 
  4.  
  5.     @Bean 
  6.     public HikariDataSource masterDataSource(RWDataSourceProperties rwDataSourceProperties) { 
  7.         return new HikariDataSource(rwDataSourceProperties.getMaster()) ; 
  8.     } 
  9.      
  10.     @Bean 
  11.     public List<HikariDataSource> slaveDataSources(RWDataSourceProperties rwDataSourceProperties) { 
  12.         List<HikariDataSource> lists = new ArrayList<>() ; 
  13.         for(HikariConfig config : rwDataSourceProperties.getSlaves()) { 
  14.             lists.add(new HikariDataSource(config)) ; 
  15.         } 
  16.         return lists ; 
  17.     } 
  18.      
  19.     @Bean 
  20.   @Primary 
  21.     @DependsOn({"masterDataSource""slaveDataSources"}) 
  22.     public AbstractRoutingDataSource routingDataSource(@Qualifier("masterDataSource")DataSource masterDataSource, 
  23.             @Qualifier("slaveDataSources")List<HikariDataSource> slaveDataSources) { 
  24.         BaseRoutingDataSource ds = new BaseRoutingDataSource() ; 
  25.         Map<Object, Object> targetDataSources = new HashMap<>(2) ; 
  26.         targetDataSources.put("master", masterDataSource) ; 
  27.         for (int i = 0; i < slaveDataSources.size(); i++) { 
  28.             targetDataSources.put("slave-" + i, slaveDataSources.get(i)) ; 
  29.         } 
  30.         ds.setDefaultTargetDataSource(masterDataSource) ; 
  31.         ds.setTargetDataSources(targetDataSources) ; 
  32.         return ds ; 
  33.     } 
  34.      

 5.數據源路由

  1. public class BaseRoutingDataSource extends AbstractRoutingDataSource { 
  2.  
  3.     @Resource 
  4.     private DataSourceHolder holder; 
  5.      
  6.     @Override 
  7.     protected Object determineCurrentLookupKey() { 
  8.         return holder.get() ; 
  9.     } 
  10.      

  1. public class DataSourceHolder { 
  2.      
  3.     private ThreadLocal<Integer> context = new ThreadLocal<Integer>() { 
  4.         @Override 
  5.         protected Integer initialValue() { 
  6.             return 0 ; 
  7.         } 
  8.     }; 
  9.      
  10.     @Resource 
  11.     private BaseSlaveLoad slaveLoad ; 
  12.      
  13.     public String get() { 
  14.         Integer type = context.get() ; 
  15.         return type == null || type == 0 ? "master" : "slave-" + slaveLoad.load() ; 
  16.     } 
  17.      
  18.     public void set(Integer type) { 
  19.         context.set(type) ; 
  20.     } 
  21.      

 通過aop動態設置context的內容值,0為從寫庫中操作,其它的都在讀庫中操作。

BaseSlaveLoad類為到底從那個讀庫中選取的一個算法類,默認實現使用的是輪詢算法。

  1. public interface BaseSlaveLoad { 
  2.  
  3.     int load() ; 
  4.      

  1. public abstract class AbstractSlaveLoad implements BaseSlaveLoad { 
  2.  
  3.     @Resource 
  4.     protected List<HikariDataSource> slaveDataSources ; 
  5.      

 這里定義一個抽象類注入了讀庫列表,所有的實現類從該類中繼承即可。

  1. public class PollingLoad extends AbstractSlaveLoad { 
  2.      
  3.     private int index = 0 ; 
  4.     private int size = 1 ; 
  5.      
  6.     @PostConstruct 
  7.     public void init() { 
  8.         size = slaveDataSources.size() ; 
  9.     } 
  10.      
  11.     @Override 
  12.     public int load() { 
  13.         int n = index ; 
  14.         synchronized (this) { 
  15.             index = (++index) % size ; 
  16.         } 
  17.         return n ; 
  18.     } 
  19.      

 配置成Bean

  1. @Bean 
  2.     @ConditionalOnMissingBean 
  3.     public BaseSlaveLoad slaveLoad() { 
  4.         return new PollingLoad() ; 
  5.     } 
  6.      
  7.     @Bean 
  8.     public DataSourceHolder dataSourceHolder() { 
  9.         return new DataSourceHolder() ; 
  10.     } 

 6.數據源AOP

  1. public class DataSourceAspect implements MethodInterceptor { 
  2.  
  3.     private DataSourceHolder holder ; 
  4.      
  5.     public DataSourceAspect(DataSourceHolder holder) { 
  6.         this.holder = holder ; 
  7.     } 
  8.      
  9.     @Override 
  10.     public Object invoke(MethodInvocation invocation) throws Throwable { 
  11.         Method method = invocation.getMethod() ; 
  12.         String methodName = method.getName() ; 
  13.         SlaveDB slaveDB = method.getAnnotation(SlaveDB.class) ; 
  14.         if (slaveDB == null) { 
  15.             slaveDB = method.getDeclaringClass().getAnnotation(SlaveDB.class) ; 
  16.         } 
  17.         if (methodName.startsWith("find")  
  18.                 || methodName.startsWith("get"
  19.                 || methodName.startsWith("query"
  20.                 || methodName.startsWith("select"
  21.                 || methodName.startsWith("list"
  22.                 || slaveDB != null) { 
  23.             holder.set(1) ; 
  24.         } else { 
  25.             holder.set(0) ; 
  26.         } 
  27.         return invocation.proceed(); 
  28.     } 
  29.  

 應該切點需要動態配置,所以這里采用spring aop的方式來配置

  1. @Bean 
  2.     public AspectJExpressionPointcutAdvisor logAdvisor(RWDataSourceProperties props, DataSourceHolder holder) { 
  3.         AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor() ; 
  4.         logger.info("執行表達式:{}", props.getPointcut()) ; 
  5.         advisor.setExpression(props.getPointcut()) ; 
  6.         advisor.setAdvice(new DataSourceAspect(holder)) ; 
  7.         return advisor ; 
  8.     } 

 7.Enable開啟功能

  1. public class RWImportSelector implements ImportSelector { 
  2.  
  3.     @Override 
  4.     public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
  5.         return new String[] {RWConfig.class.getName()} ; 
  6.     } 
  7.  

 這里的RWConfig為我們上面的配置類

  1. @Retention(RetentionPolicy.RUNTIME) 
  2. @Target(ElementType.TYPE) 
  3. @Documented 
  4. @Import({RWImportSelector.class}) 
  5. public @interface EnableRW { 

  1. @Documented 
  2. @Retention(RUNTIME) 
  3. @Target({ TYPE, METHOD }) 
  4. public @interface SlaveDB { 

 有@SlaveDB的注解方法會類都會從讀庫中操作。

到此讀寫分離組件開發完成。

8.打包安裝到本地倉庫

  1. mvn install -Dmaven.test.skip=true 

9.新建base-web項目

引入依賴

  1. <dependency> 
  2.             <groupId>com.pack</groupId> 
  3.             <artifactId>xg-component-rw</artifactId> 
  4.             <version>1.0.0</version> 
  5. </dependency> 

 啟動類添加注解開啟讀寫分離功能

  1. @SpringBootApplication 
  2. @EnableRW 
  3. public class BaseWebApplication { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(BaseWebApplication.class, args); 
  7.     } 
  8.  

 測試:

第一次查詢:

第二次查詢:

為了區別兩個從庫設置不同的數據

這里是寫庫

完畢!!!

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2023-07-07 08:36:45

配置注解jar

2020-04-23 15:08:41

SpringBootMyCatJava

2021-06-25 10:05:58

SpringBootMySQL數據庫

2011-08-30 12:49:59

Mysql ProxyLua分離

2024-05-31 13:34:57

2019-09-30 09:19:54

Redis分離云數據庫

2011-08-22 12:01:38

iPhone開發文件

2018-10-16 16:45:05

數據庫讀寫分離

2011-08-10 16:27:07

Cocoa TouchPlist

2009-05-04 09:13:52

PHPMySQL讀寫分離

2018-01-01 05:23:13

服務化讀寫分離架構

2017-09-04 09:53:58

MySQLAtlasNavicat

2010-05-17 11:19:44

MySQL proxy

2017-05-25 10:22:13

NoSQL數據庫主主備份

2022-04-25 08:03:57

MySQL中間件MyCat

2009-04-10 09:06:16

Windows Emb

2020-02-28 19:06:21

緩存讀寫Redis

2021-09-08 10:23:08

讀寫分離Java數據庫

2022-06-20 14:59:14

讀寫分離模Loki

2023-02-01 07:34:41

讀寫分離數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91在线视频观看 | 国产色网 | 久草在线在线精品观看 | 国产福利在线视频 | 国产电影一区二区 | 精品日韩欧美一区二区 | 精品无码久久久久久国产 | 国产乱码久久久久久一区二区 | 国产成人精品一区二 | 国产精品中文字幕在线观看 | 亚洲成人av| 成人精品一区亚洲午夜久久久 | 中文字幕日韩欧美一区二区三区 | 国产一区久久 | 久久亚洲国产精品 | 一区二区在线不卡 | 国产成人精品午夜视频免费 | 亚洲精品电影在线观看 | 伊人久久精品 | 精品视频在线观看 | 成人av免费| 国产韩国精品一区二区三区 | 99爱在线观看 | 国产草草视频 | 久久精品免费 | 欧美在线观看一区二区 | 九色网址 | 99热视 | 欧美在线一区二区三区 | 91久久精品一区二区二区 | 国产999精品久久久久久 | 中文字幕1区2区3区 日韩在线视频免费观看 | 午夜精品久久久久久久99黑人 | 在线一区视频 | 成人在线网 | 成人av播放 | 又黄又色| 亚洲成人一区二区在线 | 国产精品国产三级国产aⅴ入口 | 国产精品一区在线 | 日韩欧美高清dvd碟片 |