2023-07-07 09:18:11來源:實(shí)戰(zhàn)案例錦集
實(shí)現(xiàn)目標(biāo):一寫多讀,讀可以任意配置多個,默認(rèn)都是從寫庫中進(jìn)行操作,只有符合條件的方法(指定的目標(biāo)方法或者標(biāo)有指定注解的方法才會從讀庫中操作)。獨(dú)立打成一個jar包放入本地倉庫。
(資料圖)
實(shí)現(xiàn)原理:通過aop。
pom.xml配置文件 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-configuration-processor true
application.yml配置文件pack: datasource: pointcut: execution(public * net.greatsoft.service.base.*.*(..)) || execution(public * net.greatsoft.service.xxx.*.*(..)) master: driverClassName: oracle.jdbc.driver.OracleDriver jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl username: test password: test minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL slaves: - driverClassName: oracle.jdbc.driver.OracleDriver jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl username: dc password: dc minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL - driverClassName: oracle.jdbc.driver.OracleDriver jdbcUrl: jdbc:oracle:thin:@10.100.102.113:1521/orcl username: empi password: empi minimumIdle: 10 maximumPoolSize: 200 autoCommit: true idleTimeout: 30000 poolName: MbookHikariCP maxLifetime: 1800000 connectionTimeout: 30000 connectionTestQuery: SELECT 1 FROM DUAL
pointcut:定義切點(diǎn),那些方法是需要攔截(從讀庫中操作)。
master:寫庫配置。
slaves:讀庫配置(List集合)。
屬性配置類@Component@ConfigurationProperties(prefix = "pack.datasource")public class RWDataSourceProperties { private String pointcut ; private HikariConfig master ; private List slaves = new ArrayList<>(); }
讀寫配置類public class RWConfig { private static Logger logger = LoggerFactory.getLogger(RWConfig.class) ; @Bean public HikariDataSource masterDataSource(RWDataSourceProperties rwDataSourceProperties) { return new HikariDataSource(rwDataSourceProperties.getMaster()) ; } @Bean public List slaveDataSources(RWDataSourceProperties rwDataSourceProperties) { List lists = new ArrayList<>() ; for(HikariConfig config : rwDataSourceProperties.getSlaves()) { lists.add(new HikariDataSource(config)) ; } return lists ; } @Bean @Primary @DependsOn({"masterDataSource", "slaveDataSources"}) public AbstractRoutingDataSource routingDataSource(@Qualifier("masterDataSource")DataSource masterDataSource, @Qualifier("slaveDataSources")List slaveDataSources) { BaseRoutingDataSource ds = new BaseRoutingDataSource() ; Map
數(shù)據(jù)源路由public class BaseRoutingDataSource extends AbstractRoutingDataSource { @Resource private DataSourceHolder holder; @Override protected Object determineCurrentLookupKey() { return holder.get() ; } }
public class DataSourceHolder { private ThreadLocal context = new ThreadLocal() { @Override protected Integer initialValue() { return 0 ; } }; @Resource private BaseSlaveLoad slaveLoad ; public String get() { Integer type = context.get() ; return type == null || type == 0 ? "master" : "slave-" + slaveLoad.load() ; } public void set(Integer type) { context.set(type) ; } }
通過aop動態(tài)設(shè)置context的內(nèi)容值,0為從寫庫中操作,其它的都在讀庫中操作。
BaseSlaveLoad類為到底從那個讀庫中選取的一個算法類,默認(rèn)實(shí)現(xiàn)使用的是輪詢算法。
public interface BaseSlaveLoad { int load() ; }public abstract class AbstractSlaveLoad implements BaseSlaveLoad { @Resource protected List slaveDataSources ; }
這里定義一個抽象類注入了讀庫列表,所有的實(shí)現(xiàn)類從該類中繼承即可。
public class PollingLoad extends AbstractSlaveLoad { private int index = 0 ; private int size = 1 ; @PostConstruct public void init() { size = slaveDataSources.size() ; } @Override public int load() { int n = index ; synchronized (this) { index = (++index) % size ; } return n ; } }
配置成Bean
@Bean@ConditionalOnMissingBeanpublic BaseSlaveLoad slaveLoad() { return new PollingLoad() ;} @Beanpublic DataSourceHolder dataSourceHolder() { return new DataSourceHolder() ;}
數(shù)據(jù)源AOPpublic class DataSourceAspect implements MethodInterceptor { private DataSourceHolder holder ; public DataSourceAspect(DataSourceHolder holder) { this.holder = holder ; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod() ; String methodName = method.getName() ; SlaveDB slaveDB = method.getAnnotation(SlaveDB.class) ; if (slaveDB == null) { slaveDB = method.getDeclaringClass().getAnnotation(SlaveDB.class) ; } if (methodName.startsWith("find") || methodName.startsWith("get") || methodName.startsWith("query") || methodName.startsWith("select") || methodName.startsWith("list") || slaveDB != null) { holder.set(1) ; } else { holder.set(0) ; } return invocation.proceed(); }}
應(yīng)該切點(diǎn)需要動態(tài)配置,所以這里采用spring aop的方式來配置
@Beanpublic AspectJExpressionPointcutAdvisor logAdvisor(RWDataSourceProperties props, DataSourceHolder holder) { AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor() ; logger.info("執(zhí)行表達(dá)式:{}", props.getPointcut()) ; advisor.setExpression(props.getPointcut()) ; advisor.setAdvice(new DataSourceAspect(holder)) ; return advisor ;}
Enable開啟功能public class RWImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[] {RWConfig.class.getName()} ; }}
這里的RWConfig為我們上面的配置類
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import({RWImportSelector.class})public @interface EnableRW {}@Documented@Retention(RUNTIME)@Target({ TYPE, METHOD })public @interface SlaveDB {}
有@SlaveDB的注解方法或類都會從讀庫中操作。
到此讀寫分離組件開發(fā)完成。
打包安裝到本地倉庫mvn install -Dmaven.test.skip=true
新建base-web項(xiàng)目引入依賴
com.pack xg-component-rw 1.0.0
啟動類添加注解開啟讀寫分離功能
@SpringBootApplication@EnableRWpublic class BaseWebApplication { public static void main(String[] args) { SpringApplication.run(BaseWebApplication.class, args); }}
測試:
第一次查詢:
圖片
第二次查詢:
圖片
為了區(qū)別兩個從庫設(shè)置不同的數(shù)據(jù)
這里是寫庫
關(guān)鍵詞:
實(shí)現(xiàn)目標(biāo):一寫多讀,讀可以任意配置多個,默認(rèn)都是從寫庫中進(jìn)行操作,
在Java中,繼承是面向?qū)ο缶幊讨械囊粋€重要概念,它允許一個類(稱為子
寫過爬蟲的同學(xué)都知道,當(dāng)我們想對App或者小程序進(jìn)行抓包時(shí),最常用的
面對教育數(shù)字化轉(zhuǎn)型需要,重慶工商職業(yè)學(xué)院較早認(rèn)識到數(shù)字化賦能專業(yè)高
楊知寒,女,生于一九九四年,中國作家協(xié)會會員。作品見于《人民文學(xué)》
7月5日,在全球數(shù)字經(jīng)濟(jì)大會·數(shù)字經(jīng)濟(jì)賦能種業(yè)振興專題論壇上,中國科
在青海湖邊拍攝的棕頭鷗。記者張宏祥攝青海湖裸鯉救護(hù)中心循環(huán)水車間。
為落實(shí)全國城市生活垃圾宣傳周活動要求,天津市分類辦組織全市社會公眾
一、繼承權(quán)遺產(chǎn)怎么分配繼承權(quán)遺產(chǎn)分配的方法如下:1 同一順序繼承人繼
蘇南京江北新區(qū)屬于哪個區(qū),哈爾濱江北屬于哪個區(qū)這個問題很多朋友還不
中國商業(yè)聯(lián)合會6日發(fā)布7月中國零售業(yè)景氣指數(shù)(CRPI)。7月,中國零售業(yè)
江上沒有描寫小孩?!督稀肥翘拼娙死钌屉[創(chuàng)作的一首五言律詩。此詩
1、打開電腦管家,選擇“電腦診斷”一欄; 2、找到桌面圖標(biāo)后,選擇其
中新社北京7月6日電 (記者 王恩博)中國國家金融監(jiān)管總局6日對外發(fā)
iPhone15系列將于8月量產(chǎn):ProMax或要漲價(jià)成史上最貴