1. 程式人生 > >springboot環境下實現讀寫分離

springboot環境下實現讀寫分離

本文講述springboot環境下構造讀寫分離的框架;

讀寫分離 有哪些好處呢,相信不用多講,大家能夠花時間看這篇文章,那麼就很清楚它的應用場景了,下面我們開始直接進入正題;

讀寫分離其實就是在底層替換資料來源即可,針對一主一從的情況下資料來源切換比較簡單,那麼在一主多從的情況下如何有效的切換資料來源則是一件很頭疼的事情,簡單的演算法可以用隨機,稍微改進則可以用輪尋,再改進的是不是可以用minCollectsUsed?針對這些情況還是看業務場景決定吧;

目前講述的是一主一從的情況下

下面是根據一主一從的場景下講述:

首先要了解什麼時候切換,如何切換

在所有的讀的時候進行切換,在update,delete,savfe的時候進行切換;如何判斷這些呢?若是在叢集的環境下我們可以通過路由控制服務的走向,在服務段配置下即可;但是這樣移植性比較差;在不汙染程式碼的同時我們可以採用AOP定義切入點來實現;實現方式如下:

@Pointcut("execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.list*(..)) ||execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.count*(..))||execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.pager*(..))")  
 public void slavePointCut(){}
 
 @Pointcut("execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.save*(..)) || execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.delete*(..))||execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.update*(..))||execution(* com.xx.wdcloud.mybatis.dao.impl.BaseDaoImpl.batchDelete*(..))")
 public void masterPointCut(){}
 
 
/*@Before("slavePointCut()")
public void setSlaveDataSouce(){
DataSourceContextHolder.read();
}
@Before("masterPointCut()")
public void setMasterDataSource(){
DataSourceContextHolder.write();
}*/
@Around("slavePointCut()")
public Object processedSlave(ProceedingJoinPoint point) throws Throwable{
try{
System.out.println("--------------------------->set database source is slave");
DataSourceContextHolder.read();
Object result=point.proceed();
return result;
}finally {
DataSourceContextHolder.removeDataSource();
}
}
@Around("masterPointCut()")
public Object processedMaster(ProceedingJoinPoint point) throws Throwable{
try{
System.out.println("---------------------------->set database source is master");
DataSourceContextHolder.write();
Object result=point.proceed();
return result;
}finally {
DataSourceContextHolder.removeDataSource();
}
}
aop的兩種方式都可以實現(before和around),註釋的是一種,可跟根據自己需求選擇,在上述程式碼中有一個DatasourceContextHolder的類,裡面定一個了一個執行緒副本,來存放讀寫的資訊,程式碼如下:
public class DataSourceContextHolder {
private static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class);
private static final ThreadLocal<String> local=new ThreadLocal<String>();
public static void read(){
log.info("------------》切換到讀庫");
local.set(DataSourceType.slaveDataSource.getDataSource());
}
public static void write(){
log.info("------------》切換到寫庫");
local.set(DataSourceType.masterDataSource.getDataSource());
}
public static String getCurrentDataSource(){
log.info("------------》getCurrentDataSource");
return local.get();
}
public static void removeDataSource(){
local.remove();
}
threadlocal的用法不多做解釋,網上很多人的部落格講述的很詳細;但是需要說明的一點,它不是本地執行緒這樣來說的。。。因為在和很多人交流的時候,他們都認為這是一個本地執行緒,那麼本地執行緒又是什麼意思呢,又該如何使用呢?具體的用法看下原始碼會很清晰,原始碼也不難讀懂

2.資料來源的定義以及資料來源路由的控制

資料來源的定義如下,springboot中的config資訊就是將傳統的springmvc中的xml程式碼化,看起來更方便簡介,以前在xml中尋找各種配置,那是一個頭大,現在能夠清晰明瞭的對各種進行定義,比如RedisConfig,DruidConfig等。

MyAbstractRoutingDataSource類重寫了AbstractRoutingDataSource中路由資料來源;若是在多從的環境中,資料庫呼叫負載均衡的演算法則在此方法實現;有興趣的同學可以看下AbstractRoutingDataSource類,看是如何排程這個方法的;

實現程式碼如下:

protected Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
// @Scope("prototype")
/*
 * @Bean
 * 
 * @Primary public SqlSession SqlSession() throws Exception{ SqlSession
 * sqlSession=new SqlSessionTemplate(sqlSessionFactory()); return
 * sqlSession; }
 */
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
// return super.sqlSessionFactory(slaveDataSource());
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSouceProxy());
// sqlSessionFactoryBean.setTypeAliasesPackage("com.*.*");
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("/config/mybatis-config.xml"));
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean
.setMapperLocations(resourcePatternResolver.getResources("classpath*:com/xx/wdcloud/mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public AbstractRoutingDataSource dataSouceProxy() {
MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource();
Map<Object, Object> targetDataSource = new HashMap<Object, Object>();
targetDataSource.put(DataSourceType.slaveDataSource.getDataSource(), slaveDataSource());
targetDataSource.put(DataSourceType.masterDataSource.getDataSource(), masterDataSource());
proxy.setTargetDataSources(targetDataSource);
proxy.setDefaultTargetDataSource(slaveDataSource());
return proxy;
}
@Bean
public PlatformTransactionManager PlatformTransactionManager() {
return new DataSourceTransactionManager(dataSouceProxy());
}
@Value("${datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Primary
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "datasource.master")
public DataSource masterDataSource() {
logger.info("-----初始化master資料庫配置-----");
return DataSourceBuilder.create().type(dataSourceType).build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "datasource.slave")
public DataSource slaveDataSource() {
logger.info("-----初始化slave資料庫配置-----");
return DataSourceBuilder.create().type(dataSourceType).build();
}
資料來源的配置資訊如下,配置了master和slave
datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  master:
    url: jdbc:mysql://10.67.18.17:3306/xxxxxx?useUnicode:true&characterEncoding:UTF-8
    username: xxxxxxx
    password: xxxxxxx
    driver-class-name: com.mysql.jdbc.Driver
    filters: stat
    maxActive: 200
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQueryTimeout: 900000
    validationQuery: SELECT SYSDATE() from dual
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
  slave:
    url: jdbc:mysql://10.67.18.17:3306/yyyyyyyy?useUnicode:true&characterEncoding:UTF-8
    username: xxxxx
    password: xxxxxx
    driver-class-name: com.mysql.jdbc.Driver
    filters: stat
    maxActive: 200
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQueryTimeout: 900000
    validationQuery: SELECT SYSDATE() from dual
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20

大概的實現方式如上,其中在核心配置部分,可以通過實現mybatis提供的mybatisautoconfig這個類,這裡可以通過整合,然後簡化使用者的操作,針對其中的一些方法可以根據業務需求重寫來滿足自己專案的需要,這裡我沒有整合這個類。

相關推薦

springboot環境實現分離

本文講述springboot環境下構造讀寫分離的框架; 讀寫分離 有哪些好處呢,相信不用多講,大家能夠花時間看這篇文章,那麼就很清楚它的應用場景了,下面我們開始直接進入正題; 讀寫分離其實就是在底層替換資料來源即可,針對一主一從的情況下資料來源切換比較簡單,那麼在一主多從的

Linux環境mysql分離以及主從配置(不錯可以的)

記下File及Position下的值。以備在配置從伺服器時使用。 注:File:當前binlog的檔名,每重啟一次mysql,就會生成一個新binlog檔案       Position:當前binlog的指標位置 三、從伺服器配置 1、配置mysql.cnf # vi /etc/my.cnf (1)修改

SpringBoot 整合 MyCat 實現分離

MyCat一個徹底開源的,面向企業應用開發的大資料庫叢集。基於阿里開源的Cobar產品而研發。能滿足資料庫資料大量儲存;提高了查詢效能。文章介紹如何實現MyCat連線MySQL實現主從分離,並整合SpringBoot實現讀寫分離。 MySQL配置主從關係 說明 192.168.0.105 Linux 資料庫

生產環境實踐Mysql5.7主從+Atlas實現分離

pro c-c creators 日誌 可執行 公眾 var timeout 錯誤信息 Mysql主從搭建 主從復制可以使MySQL數據庫主服務器的主數據庫,復制到一個或多個MySQL從服務器從數據庫,默認情況下,復制異步; 根據配置,可以復制數據庫中的所有數據庫,選定的

windows MySQL分離、主從複製、通過amoeba代理實現分離 配置全過程

配置環境: 1.mysql5.6 2.windowsXP 主從複製配置 主伺服器配置 配置my.ini檔案 查詢my.ini地址 my.ini檔案在MySQL Server 5.6目錄下 我的my.ini路徑: C:\Documents and Settings\All

SpringBoot進行MySql動態資料來源配置實現分離(連線池Druid)

1.簡介 前面使用C3P0連線池進行過資料庫的讀寫分離的實驗,今天換一下資料庫連線池改造一下,原理還是和原來的一樣。 Druid是阿里出品,淘寶和支付寶專用資料庫連線池,但它不僅僅是一個數據庫連線池,它還包含一個ProxyDriver,一系列內建的JDBC元

springboot mysql 多資料來源配置,可實現分離

1、程式碼實現 import com.zaxxer.hikari.HikariDataSource; import javas

springboot實現分離(基於Mybatis,mysql)

近日工作任務較輕,有空學習學習技術,遂來研究如果實現讀寫分離。這裡用部落格記錄下過程,一方面可備日後檢視,同時也能分享給大家(網上的資料真的大都是抄來抄去,,還不帶格式的,看的真心難受)。 完整程式碼:https://github.com/FleyX/demo-project/tree/master/dxfl

Springboot + Mysql8實現分離

在實際的生產環境中,為了確保資料庫的穩定性,我們一般會給資料庫配置雙機熱備機制,這樣在master資料庫崩潰後,slave資料庫可以立即切換成主資料庫,通過主從複製的方式將資料從主庫同步至從庫,在業務程式碼中編寫程式碼實現讀寫分離(讓主資料庫處理 事務性增、改、刪操作,而從資料庫處理查詢操作)來提升資料庫的併

分庫分表(3) ---SpringBoot + ShardingSphere 實現分離

分庫分表(3)---ShardingSphere實現讀寫分離 有關ShardingSphere概念前面寫了兩篇部落格: 1、分庫分表(1) --- 理論 2、 分庫分表(2) --- ShardingSphere(理論) 下面就這個專案做個整體簡單介紹,並在文章最下方附上專案Github地址。 一、專案概

mysql+mysql_proxy實現分離

mysql-_proxymysql讀寫分離需要基於主從架構實現 mysql主從配置:http://hongchen99.blog.51cto.com/12534281/1917137 mysql-proxy:用於實現mysql主從分離,基於主從架構讀寫分離存在的最大問題就是主從同步延遲 安裝my

使用spring實現分離

item ger [] 依據 sign batis repl arch 定義 1. 背景 我們一般應用對數據庫而言都是“讀多寫少”,也就說對數據庫讀取數據的壓力比較大,有一個思路就是說采用數據庫集群的方案, 其中一個是主庫,負責寫入數據,我們稱之為:寫庫; 其它都是從庫,

Spring動態數據源實現分離

character count 方法 cdata mas ebe aso nds evict 一、創建基於ThreadLocal的動態數據源容器,保證數據源的線程安全性 package com.bounter.mybatis.extension; /** * 基

Mysql主從配置,實現分離

windows安裝 建議 xid 分布式 唯一標識 -1 在線下載 命令 進行 大型網站為了軟解大量的並發訪問,除了在網站實現分布式負載均衡,遠遠不夠。到了數據業務層、數據訪問層,如果還是傳統的數據結構,或者只是單單靠一臺服務器扛,如此多的數據庫連接操作,數據庫必然會崩潰,

Mycat實現分離(一)

mycatMycat介紹Mycat是一個國產中間件產品,作用在應用層和數據庫之間架橋,使應用通過MyCat來對後端數據庫進行管理,是一款國人自主的開源的中間件產品。算是比較優秀的一款,前身是阿裏公司在維護,很多公司也慢慢的在嘗試接入這個產品,但不得不說官方文檔似乎做的不太友好。至於為什麽選擇MyCat可能只有

MySQL主從復制 + Mycat實現分離

date windows repl ron 信息 決定 不用 ati 刪掉 說明:兩臺MySQL服務器都是使用CentOS6.5系統,MySQL版本為mysql-5.7.17 MySQL一主一被實現主從復制 註意:寫包括insert,delete,update 操作;讀只有

使用Spring實現分離( MySQL實現主從復制)

sign eve replicat win [] 做了 用戶名 指定 ati 1. 背景 我們一般應用對數據庫而言都是“讀多寫少”,也就說對數據庫讀取數據的壓力比較大,有一個思路就是說采用數據庫集群的方案, 其中一個是主庫,負責寫入數據,我們稱之為:寫庫; 其它都是從庫,

sharding-JDBC 實現分離

aso engine lec bus manage 均衡 map 如果 use 需求 一主兩從,做讀寫分離。 多個從庫之間實現負載均衡。 可手動強制部分讀請求到主庫上。(因為主從同步有延遲,對實時性要求高的系統,可以將部分讀請求也走主庫) 本次不討論 MySQL如何配置

使用Spring+MySql實現分離(二)spring整合多數據庫

ont 依據 xml配置 實現 整合 配置 item 匹配 mic 緊接著上一章,因為現在做的項目還是以spring為主要的容器管理框架,所以寫以下spring如何整合多個數據源。 1. 背景 我們一般應用對數據庫而言都是“讀多寫少”,也就說對數據庫讀取數據的壓力比較大

kylin跨集群配置實現分離

KYLIN HBASE HIVE 讀寫分離 跨集群 社區提供的讀寫分離架構圖如下:通過架構圖可以看到Kylin會訪問兩個集群的HDFS,建議兩個集群的NameService務必不能相同,尤其是集群啟用NameNode HA時,相同的NameService會導致組件在跨集群訪問HDFS時因無