JPA集成MyCAT實現讀寫分離

在高併發的互聯網項目中,數據庫的壓力一直是一個瓶頸,而大量的操作均爲讀操作,通過MySQL的讀寫分離,一主多從的當時能夠大大的降低數據庫的壓力。在之前的Springboot章節中有過類似的話題,當時我們可以通過配置多個數據源,通過不同的數據源指向實現讀寫分離,還實現了基於AOP的動態數據源切換,當然這也需要歸功於Spring提供了數據源的路由功能,不過此方式依然會對我們的業務代碼造成侵入,本章將通過MyCat實現無侵入的讀寫分離。

基礎設施

目前本地已經運行有3個實例服務
Master 127.0.0.1:3310
Slave 127.0.0.1:3321
Slave 127.0.0.1:3322
本案例主要驗證讀寫分離,故數據庫均爲springboot1,且用戶名密碼均爲root。
特殊數據,由於我們是單向的複製,故將3321中的被查詢數據的password調整爲1111,3310和3322中均爲111,後續將通過對此數據的查詢驗證。

工程改造

1、調整內容非常簡單,僅需要我們將原MySQL的連接信息替換爲MyCat的連接信息即可:
#single configure
#spring.datasource.url=jdbc:mysql://localhost:3306/springboot1?useSSL=false
#spring.datasource.username=root
#spring.datasource.password=root

#MyCat
spring.datasource.url=jdbc:mysql://localhost:8066/TESTDB?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

2、調整默認事務配置,關閉spring-data-jpa默認的事務管理機制:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(enableDefaultTransactions=false,
entityManagerFactoryRef="entityManagerFactory1",
transactionManagerRef="transactionManager1",
basePackages= { "com.shf.springboot.*","com.shf.springboot2","com.shf.springboot3.service" }//
,repositoryFactoryBeanClass=BaseRepositoryFactoryBean.class
) //設置Repository所在位置
public class JpaSource1Configuration implements Ordered {
.........................
}
在使用mycat時需要關閉spring-data-jpa默認的事務管理機制. 
原因如下:
  • mycat對於開啓了事務的查詢,插入等操作,都會走主庫
  • spring-data-jpa默認的事務管理機制對查詢操作執行的是隻讀事務,可惜只讀事務也是事務
鑑於以上兩個原因.我們就得使用enableDefaultTransactions = false來關閉spring-data-jpa默認的事務管理機制

以上就是所有的代碼改造,可以看到基本是無任何侵入的。

驗證

讀驗證
當我們執行查詢時,首次查詢

其對應的日誌記錄
2017-02-05 16:24:57.758 DEBUG [$_NIOREACTOR-3-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:341)) - release connection MySQLConnection [id=16, lastTime=1486283097750, user=root, schema=springboot1, old shema=springboot1, borrowed=true, fromSlaveDB=true, threadId=8, charset=utf8, txIsolation=3, autocommit=true, attachment=dn1{select user0_.id as id1_1_, user0_.birthday as birthday2_1_, user0_.email as email3_1_, user0_.loginname as loginnam4_1_, user0_.name as name5_1_, user0_.password as password6_1_ from t_sys_user user0_}, respHandler=SingleNodeHandler [node=dn1{select user0_.id as id1_1_, user0_.birthday as birthday2_1_, user0_.email as email3_1_, user0_.loginname as loginnam4_1_, user0_.name as name5_1_, user0_.password as password6_1_ from t_sys_user user0_}, packetId=-127], host=127.0.0.1, port=3322, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
再次查詢

此次的日誌記錄
2017-02-05 16:34:22.843 DEBUG [$_NIOREACTOR-2-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:341)) - release connection MySQLConnection [id=14, lastTime=1486283662774, user=root, schema=springboot1, old shema=springboot1, borrowed=true, fromSlaveDB=false, threadId=5, charset=utf8, txIsolation=3, autocommit=true, attachment=dn1{select user0_.id as id1_1_, user0_.birthday as birthday2_1_, user0_.email as email3_1_, user0_.loginname as loginnam4_1_, user0_.name as name5_1_, user0_.password as password6_1_ from t_sys_user user0_}, respHandler=SingleNodeHandler [node=dn1{select user0_.id as id1_1_, user0_.birthday as birthday2_1_, user0_.email as email3_1_, user0_.loginname as loginnam4_1_, user0_.name as name5_1_, user0_.password as password6_1_ from t_sys_user user0_}, packetId=-127], host=localhost, port=3321, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
可以看到兩次的查詢記錄並不相同,但與我們預設的從庫數據是對應的,說明我們的查詢確實是從Slave庫讀取。

寫驗證
當我們單元測試新增時
@Test
public void testUserSave(){
try{
List<User> list=new ArrayList<User>(10);
list.add(new User("11121","11221"));
list.add(new User("22222","222"));
list.add(new User("333","333"));
userService.save(list);
}catch(Exception e){
e.printStackTrace();
}
}
我們查看日誌
2017-02-05 16:19:46.367 DEBUG [$_NIOREACTOR-0-RW] (io.mycat.server.NonBlockingSession.releaseConnection(NonBlockingSession.java:341)) - release connection MySQLConnection [id=8, lastTime=1486282786334, user=root, schema=springboot1, old shema=springboot1, borrowed=true, fromSlaveDB=false, threadId=13, charset=utf8, txIsolation=3, autocommit=false, attachment=dn1{insert into t_sys_user (loginname, password) values ('333', '333')}, respHandler=io.mycat.backend.mysql.nio.handler.CommitNodeHandler@3efbb1d8, host=localhost, port=3310, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
採用的爲Master庫。

總結:
1、通過MyCat在無侵入的情況下實現了讀寫分離;
2、我們需要特別注意關閉spring-data-jpa默認的事務管理機制即可,在業務層使用@Transactional註解來進行聲明式事務管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章