a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > JSP > 正文

Spring AOP切面解決數(shù)據(jù)庫讀寫分離實例詳解

2024-09-05 00:23:05
字體:
供稿:網(wǎng)友

Spring AOP切面解決數(shù)據(jù)庫讀寫分離實例詳解

為了減輕數(shù)據(jù)庫的壓力,一般會使用數(shù)據(jù)庫主從(master/slave)的方式,但是這種方式會給應(yīng)用程序帶來一定的麻煩,比如說,應(yīng)用程序如何做到把數(shù)據(jù)寫到master庫,而讀取數(shù)據(jù)的時候,從slave庫讀取。如果應(yīng)用程序判斷失誤,把數(shù)據(jù)寫入到slave庫,會給系統(tǒng)造成致命的打擊。

解決讀寫分離的方案很多,常用的有SQL解析、動態(tài)設(shè)置數(shù)據(jù)源。SQL解析主要是通過分析sql語句是insert/select/update/delete中的哪一種,從而對應(yīng)選擇主從。而動態(tài)設(shè)置數(shù)據(jù)源,則是通過攔截方法名稱的方式來決定主從的,例如:save*(),insert*() 形式的方法使用master庫,select()開頭的,使用slave庫。蠻多公司會使用在方法上標(biāo)上自定義的@Master、@Slave之類的標(biāo)簽來選擇主從,也有公司直接就調(diào)用setxxMaster,setxxSlave之類的代碼進(jìn)行主從選擇。

下面我主要介紹一下基于Spring AOP動態(tài)設(shè)置數(shù)據(jù)源這種方式。注意這篇文章是基于自己項目的實際情況的,不是通用的方案,請知曉。

原理圖

Spring,AOP,切面,數(shù)據(jù)庫,讀寫分離,AOP切面
 

Spring AOP的切面主要的職責(zé)是攔截Mybatis的Mapper接口,通過判斷Mapper接口中的方法名稱來決定主從。

 Spring AOP 切面配置

<aop:config expose-proxy="true">  <aop:pointcut id="txPointcut" expression="execution(* com.test..persistence..*.*(..))" />  <aop:aspect ref="readWriteInterceptor" order="1">  <aop:around pointcut-ref="txPointcut" method="readOrWriteDB"/>  </aop:aspect>  </aop:config>     <bean id="readWriteInterceptor" class="com.test.ReadWriteInterceptor">    <property name="readMethodList">     <list>      <value>query*</value>      <value>use*</value>      <value>get*</value>      <value>count*</value>      <value>find*</value>      <value>list*</value>      <value>search*</value>    </list>   </property>  <property name="writeMethodList">    <list>      <value>save*</value>      <value>add*</value>      <value>create*</value>      <value>insert*</value>      <value>update*</value>      <value>merge*</value>      <value>del*</value>      <value>remove*</value>      <value>put*</value>      <value>write*</value>    </list>  </property>  </bean> 

把所有Mybatis接口類都放置在persistence下。配置的切面類是ReadWriteInterceptor。這樣當(dāng)Mapper接口的方法被調(diào)用時,會先調(diào)用這個切面類的readOrWriteDB方法。在這里需要注意<aop:aspect>中的order="1" 配置,主要是為了解決切面于切面之間的優(yōu)先級問題,因為整個系統(tǒng)中不太可能只有一個切面類。

Spring AOP 切面類實現(xiàn)

public class ReadWriteInterceptor {   private static final String DB_SERVICE = "dbService";   private List<String> readMethodList = new ArrayList<String>();   private List<String> writeMethodList = new ArrayList<String>(); 
  public Object readOrWriteDB(ProceedingJoinPoint pjp) throws Throwable {     String methodName = pjp.getSignature().getName();     if (isChooseReadDB(methodName)) {       //選擇slave數(shù)據(jù)源     } else if (isChooseWriteDB(methodName)) {       //選擇master數(shù)據(jù)源     } else {      //選擇master數(shù)據(jù)源     }     return pjp.proceed(); }   private boolean isChooseWriteDB(String methodName) {    for (String mappedName : this.writeMethodList) {      if (isMatch(methodName, mappedName)) {        return true;      }    }   return false; }   private boolean isChooseReadDB(String methodName) {   for (String mappedName : this.readMethodList) {     if (isMatch(methodName, mappedName)) {       return true;     }   }   return false; }   private boolean isMatch(String methodName, String mappedName) {   return PatternMatchUtils.simpleMatch(mappedName, methodName); }   public List<String> getReadMethodList() {   return readMethodList;  }   public void setReadMethodList(List<String> readMethodList) {   this.readMethodList = readMethodList; }   public List<String> getWriteMethodList() {   return writeMethodList;  }   public void setWriteMethodList(List<String> writeMethodList) {   this.writeMethodList = writeMethodList; }  

覆蓋DynamicDataSource類中的getConnection方法

ReadWriteInterceptor中的readOrWriteDB方法只是決定選擇主還是從,我們還必須覆蓋數(shù)據(jù)源的getConnection方法,以便獲取正確的connection。一般來說,是一主多從,即一個master庫,多個slave庫的,所以還得解決多個slave庫之間負(fù)載均衡、故障轉(zhuǎn)移以及失敗重連接等問題。

1、負(fù)載均衡問題,slave不多,系統(tǒng)并發(fā)讀不高的話,直接使用隨機(jī)數(shù)訪問也是可以的。就是根據(jù)slave的臺數(shù),然后產(chǎn)生隨機(jī)數(shù),隨機(jī)的訪問slave。

2、故障轉(zhuǎn)移,如果發(fā)現(xiàn)connection獲取不到了,則把它從slave列表中移除,等其回復(fù)后,再加入到slave列表中

3、失敗重連,第一次連接失敗后,可以多嘗試幾次,如嘗試10次。

處理業(yè)務(wù)方法中的@Transactional注解

我參與的這個項目,大部分業(yè)務(wù)代碼是不需要事務(wù)的,只有極個別情況需要。那么按照上面提到的方案,如果不對業(yè)務(wù)方法中@Transactional注解進(jìn)行特殊處理的話,主從的選擇會出現(xiàn)問題。大家都知道,如果使用了Spring的事務(wù),那么在同一個業(yè)務(wù)方法內(nèi),只會調(diào)用一次數(shù)據(jù)源的getConnection方法,如果該業(yè)務(wù)方法內(nèi),調(diào)用的mapper接口剛好以select開頭的,就會選擇slave庫,那么接下來調(diào)用以insert開頭的mapper接口方法時,會把數(shù)據(jù)寫入到slave庫。如何解決這個問題呢?必須在進(jìn)入標(biāo)有@Transactional注解的業(yè)務(wù)方法前,指定選擇master主庫。可以通過覆蓋DataSourceTransactionManager類中的doBegin方法,如下:

public class MyTransactionManager extendsDataSourceTransactionManager{  @Override  protected void doBegin(Object transaction, TransactionDefinitiondefinition) {  //選擇master數(shù)據(jù)庫  super.doBegin(transaction, definition);  }  } 

這樣既可以避免,把數(shù)據(jù)寫入到從庫的問題。

總結(jié)

本人的解決方案是基于項目實際的,不一定合適你,我只是展示了解決方案而已。當(dāng)然你可以選擇開源的框架,像阿里的Cobar,360的Atlas。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!


注:相關(guān)教程知識閱讀請移步到JSP教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 中文字幕爱爱视频 | 超碰成人97 | 久久精品 | 亚洲欧美中文日韩在线v日本 | 成人超碰在线 | 日韩精品在线观看一区二区 | 国产一级在线观看 | 美女又黄又免费 | 久热在线视频 | 亚洲欧美日韩另类精品一区二区三区 | 日韩精品一区二区三区 | 99reav| 97在线观看视频 | 成人在线欧美 | 色综合免费视频 | 精品一区二区不卡 | 国产一区免费在线观看 | 久久久久久免费毛片精品 | 国产日本欧美一区二区三区 | 日韩精品免费在线观看 | 久久久久免费观看 | 日本黄色免费网站 | 国产在线精品成人免费怡红院 | 婷婷色综合 | 精品国产一区二区在线 | 成人毛片在线免费看 | 国产精品久久久久久久久久三级 | 91久久久久久久久 | 狠狠躁夜夜躁人人爽天天天天97 | av在线免费观看网址 | 黄色网址网站 | 日韩在线小视频 | 国产九九精品视频 | 色婷婷亚洲国产女人的天堂 | 欧美性猛交一区二区三区精品 | 精品国产福利 | 亚洲第一色 | 欧美成人精品一区二区男人看 | 日韩美女国产精品 | 日韩在线国产 | 九九久久免费视频 |