02-下篇-SpringBoot下MySQL的讀寫分離
2.定義資料庫的型別列舉類DataSourceType:
package com.ddbin.frms.config.datasource; import lombok.AllArgsConstructor; import lombok.Getter; /** * Description:資料來源型別的列舉類 * * @param * @author dbdu * @date 18-7-14 上午8:05 */ @Getter @AllArgsConstructor public enum DataSourceType { read("read", "從庫"), write("write", "主庫"); /** * Description:型別,是讀還是寫 * * @author dbdu * @date 18-7-14 上午8:14 */ private String type; /** * Description:資料來源的名稱 * * @author dbdu * @date 18-7-14 上午8:15 */ private String name; }要注意的是:列舉例項小寫,大寫會報錯!!read("read", "從庫"), write("write", "主庫");3.多個數據源的例項化配置類DataSourceConfiguration:有多少個數據源,就配置多少個對應的Bean。
package com.ddbin.frms.config.datasource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; /** * Description:MySQL讀寫主從資料庫源配置 * * @param * @author dbdu * @date 18-7-14 上午7:51 * @return */ @Configuration @Slf4j public class DataSourceConfiguration { @Value("${mysql.datasource.type}") private Class<? extends DataSource> dataSourceType; /** * 寫庫 資料來源配置 * * @return */ @Bean(name = "writeDataSource") @Primary @ConfigurationProperties(prefix = "mysql.datasource.write") public DataSource writeDataSource() { log.info("writeDataSource init ..."); return DataSourceBuilder.create().type(dataSourceType).build(); } /** * 有多少個從庫就要配置多少個 * * @return */ @Bean(name = "readDataSource01") @ConfigurationProperties(prefix = "mysql.datasource.read01") public DataSource readDataSourceOne() { log.info("read01 DataSourceOne init ..."); return DataSourceBuilder.create().type(dataSourceType).build(); } // @Bean(name = "readDataSource02") // @ConfigurationProperties(prefix = "mysql.datasource.read02") // public DataSource readDataSourceTwo() { // log.info("read02 DataSourceTwo init ..."); // return DataSourceBuilder.create().type(dataSourceType).build(); // } }
4.配置資料來源的切換類DataSourceContextHolder設定這個類的對應的read和write,就被內部用來讀取不同的資料來源
package com.ddbin.frms.config.datasource; import lombok.extern.slf4j.Slf4j; /** * Description:本地執行緒,資料來源上下文切換 * * @author dbdu * @date 18-7-14 上午8:17 */ @Slf4j public class DataSourceContextHolder { //線程本地環境 private static final ThreadLocal<String> local = new ThreadLocal<String>(); public static ThreadLocal<String> getLocal() { return local; } /** * 讀庫 */ public static void setRead() { local.set(DataSourceType.read.getType()); //log.info("數據庫切換到READ庫..."); } /** * 寫庫 */ public static void setWrite() { local.set(DataSourceType.write.getType()); // log.info("數據庫切換到WRITE庫..."); } public static String getReadOrWrite() { return local.get(); } public static void clear() { local.remove(); } }5.資料來源的代理路由配置DatasourceAgentConfig---請讀者特別注意這個類,網上很多說的都是mybatis框架的,這裡是SpringDataJpa框架對應的關聯代理資料來源路由的配置,此處配置出錯就會失敗!
package com.ddbin.frms.config.datasource; import com.ddbin.frms.FrmsApplication; import com.ddbin.frms.util.SpringContextsUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration @AutoConfigureAfter(DataSourceConfiguration.class) @EnableTransactionManagement(order = 10) @Slf4j public class DatasourceAgentConfig { @Value("${mysql.datasource.readSize}") private String readDataSourceSize; private AbstractRoutingDataSource proxy; @Autowired @Qualifier("writeDataSource") private DataSource writeDataSource; @Autowired @Qualifier("readDataSource01") private DataSource readDataSource01; // @Autowired // @Qualifier("readDataSource02") // private DataSource readDataSource02; /** * 把所有資料庫都放在路由中 * 重點是roundRobinDataSouceProxy()方法,它把所有的資料庫源交給AbstractRoutingDataSource類, * 並由它的determineCurrentLookupKey()進行決定資料來源的選擇,其中讀庫進行了簡單的負載均衡(輪詢)。 * * @return */ @Bean(name = "roundRobinDataSouceProxy") public AbstractRoutingDataSource roundRobinDataSouceProxy() { /** * Description:把所有資料庫都放在targetDataSources中,注意key值要和determineCurrentLookupKey()中程式碼寫的一至, * 否則切換資料來源時找不到正確的資料來源 */ Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); targetDataSources.put(DataSourceType.write.getType(), writeDataSource); targetDataSources.put(DataSourceType.read.getType() + "1", readDataSource01); //targetDataSources.put(DataSourceType.read.getType() + "2", readDataSource02); //路由類,尋找對應的數據源 final int readSize = Integer.parseInt(readDataSourceSize); MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(readSize); proxy.setTargetDataSources(targetDataSources); //默認庫 proxy.setDefaultTargetDataSource(writeDataSource); this.proxy = proxy; return proxy; } /** * Description:要特別注意,這個Bean是配置讀寫分離成敗的關鍵, * * @param [] * @return org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean * @author dbdu * @date 18-7-15 下午5:08 */ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setDatabase(Database.MYSQL); //是否生成表 vendorAdapter.setGenerateDdl(true); //是否顯示sql語句 vendorAdapter.setShowSql(true); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); //配置掃描的位置 factory.setPackagesToScan(FrmsApplication.class.getPackage().getName()); // 這個數據源設置為代理的數據源,----這是關鍵性配置!!! factory.setDataSource(proxy); return factory; } @Bean(name = "transactionManager") public MyJpaTransactionManager transactionManager() { MyJpaTransactionManager transactionManager = new MyJpaTransactionManager(); transactionManager.setDataSource(proxy); transactionManager.setEntityManagerFactory((EntityManagerFactory) SpringContextsUtil.getBean("entityManagerFactory")); return transactionManager; } }說明:entityManagerFactory是關鍵配置,網上很多說的都是mybatis的方式sqlSessionFactory的Bean會關聯代理資料來源,SpringDataJpa的方式使用entityManagerFactory來關聯代理資料來源,否則讀寫分離是假的,這個可以通過主從庫資料不同查詢可以知道!/** * Description:要特別注意,這個Bean是配置讀寫分離成敗的關鍵, * * @param []* @return org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean * @author dbdu * @date 18-7-15 下午5:08 */@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();vendorAdapter.setDatabase(Database.MYSQL);//是否生成表vendorAdapter.setGenerateDdl(true);//是否顯示sql語句vendorAdapter.setShowSql(true);LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();factory.setJpaVendorAdapter(vendorAdapter);//配置掃描的位置factory.setPackagesToScan(FrmsApplication.class.getPackage().getName());// 這個資料來源設定為代理的資料來源,----這是關鍵性配置!!!factory.setDataSource(proxy); return factory;}6.自定義的路由資料來源及事務管理器的子類:
package com.ddbin.frms.config.datasource; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * Description: 抽象資料來源的路由的子類 * Created at:2018-07-15 13:37, * by dbdu */ @Getter @Setter @AllArgsConstructor public class MyAbstractRoutingDataSource extends AbstractRoutingDataSource { /** * Description:讀庫的數量,可以用來實現負載均衡 */ private int readSize; //private AtomicLong count = new AtomicLong(0); /** * 這是AbstractRoutingDataSource類中的一個抽象方法, * 而它的返回值是你所要用的資料來源dataSource的key值,有了這個key值, * targetDataSources就從中取出對應的DataSource,如果找不到,就用配置預設的資料來源。 */ @Override protected Object determineCurrentLookupKey() { String typeKey = DataSourceContextHolder.getReadOrWrite(); if (typeKey == null || typeKey.equals(DataSourceType.write.getType())) { System.err.println("使用數據庫write............."); return DataSourceType.write.getType(); } else { //讀庫, 簡單負載均衡 // int number = count.getAndAdd(1); // int lookupKey = number % readSize; // System.err.println("使用數據庫read-" + (lookupKey + 1)); // return DataSourceType.read.getType() + (lookupKey + 1); return DataSourceType.read.getType() + "1"; } } }
package com.ddbin.frms.config.datasource; import lombok.extern.slf4j.Slf4j; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.support.DefaultTransactionStatus; @SuppressWarnings("serial") @Slf4j public class MyJpaTransactionManager extends JpaTransactionManager { @Override protected void doBegin(Object transaction, TransactionDefinition definition) { if (definition.isReadOnly()) { DataSourceContextHolder.setRead(); } else { DataSourceContextHolder.setWrite(); } log.info("jpa-transaction:begin-----now dataSource is [" + DataSourceContextHolder.getReadOrWrite() + "]"); super.doBegin(transaction, definition); } @Override protected void doCommit(DefaultTransactionStatus status) { log.info("jpa-transaction:commit-----now dataSource is [" + DataSourceContextHolder.getReadOrWrite() + "]"); super.doCommit(status); } }說明:如果方法命名不符合規則,也沒有加註解,則typeKey會有可能為null,下面的邏輯是typeKey為空使用寫庫!---也就是主庫。/** * 這是AbstractRoutingDataSource類中的一個抽象方法, * 而它的返回值是你所要用的資料來源dataSource的key值,有了這個key值, * targetDataSources就從中取出對應的DataSource,如果找不到,就用配置預設的資料來源。 */@Overrideprotected Object determineCurrentLookupKey() { String typeKey = DataSourceContextHolder.getReadOrWrite(); if (typeKey == null || typeKey.equals(DataSourceType.write.getType())) { System.err
相關推薦
02-下篇-SpringBoot下MySQL的讀寫分離
前言:關於MySQL讀寫主從實現,分兩步:第一步,需要現有主從的環境,利用docker快速實現; -----上篇第二步,利用已有的環境進行JavaEE的Web專案配置。 -----下篇,基於SpringBoot的SpringDataJpa的實現!即本文環境:Spring
springboot+ssm+mysql 讀寫分離+動態修改資料來源
一.我們最開始先實現讀寫分離(其實和多資料來源差不多,只是多資料來源的定義更加廣泛,讀寫分離只是其中的一個應用而已) 這裡就不怎麼探討mysql的主從的一個原理了,我直接貼出一個部落格,可以去看看,大致瞭解一下mysql主從。 我學東西喜歡先跑一次,如果成功了,我就再深入研究了,其實大體的邏
SpringBoot+MyBatis+MySQL讀寫分離
spring: datasource: master: jdbc-url: jdbc:mysql://192.168.102.31:3306/test username: root password: 123456 driver-cl
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
Linux環境下mysql讀寫分離以及主從配置(不錯可以的)
記下File及Position下的值。以備在配置從伺服器時使用。 注:File:當前binlog的檔名,每重啟一次mysql,就會生成一個新binlog檔案 Position:當前binlog的指標位置 三、從伺服器配置 1、配置mysql.cnf # vi /etc/my.cnf (1)修改
mysql讀寫分離之springboot整合
springboot、mysql實現讀寫分離 1、首先在springcloud config中配置讀寫資料庫 mysql: datasource: readSize: 1 #讀庫個數 type: com.alibaba.druid.pool.DruidDat
二. Mysql讀寫分離 :springboot服務端AbstractRoutingDataSource整合
一 DataSourceConfig.class /** * 資料來源配置類 */ @Configuration @EnableTransactionManagement public class DataSourceConfig { /** * 只寫資料來源
springboot環境下實現讀寫分離
本文講述springboot環境下構造讀寫分離的框架; 讀寫分離 有哪些好處呢,相信不用多講,大家能夠花時間看這篇文章,那麼就很清楚它的應用場景了,下面我們開始直接進入正題; 讀寫分離其實就是在底層替換資料來源即可,針對一主一從的情況下資料來源切換比較簡單,那麼在一主多從的
Mysql讀寫分離方案-MySQL Proxy環境部署記錄
round back 通過 and http 意思 同時 主從 角色 Mysql的讀寫分離可以使用MySQL Proxy和Amoeba實現,其實也可以使用MySQL-MMM實現讀寫分離的自動切換。MySQL Proxy有一項強大功能是實現"讀寫分離",基本原理是讓主數據
amoeba實現mysql讀寫分離+主從復制架構
mysql amoeba 讀寫分離 主從復制一、環境系統:centos6.5mysql版本:mysql5.6master服務器:192.168.1.21slave服務器: 192.168.1.100master寫 slave讀二、實現mysql主從復制在master的/etc/my.cnf中[mysqld]字
mysql中間件amoeba實現mysql讀寫分離
ipaddress -c export div 高可用 rop 6.0 res grant Amoeba是一個以MySQL為底層數據存儲,並相應用提供MySQL協議接口的proxy。它集中地響應應用的請求,根據用戶事先設置的規則。將SQL請求發送到特定的數據庫上運行
mysql讀寫分離的三種實現方式
不能 span bsp 缺點 解決方案 使用 隨機 mas 均衡 1 程序修改mysql操作類可以參考PHP實現的Mysql讀寫分離,阿權開始的本項目,以php程序解決此需求。優點:直接和數據庫通信,簡單快捷的讀寫分離和隨機的方式實現的負載均衡,權限獨立分配缺點:自己維
mysql讀寫分離
mysql amabeamoeba 實現 mysql 讀寫分離Amoeba 其實是一個代理,接收所有請求,將其分類,根據我們寫在 xml 文件裏的規則,將其投放出去,比如讀寫分離,將所有的寫操作投放給 master,將所有的讀操作投放給 slave,最後再由他返回給用戶. 讀寫分離能有效利用 mysql 主從
mycat實現MySQL讀寫分離
mycat mysql讀寫分離 mycat實現MySQL讀寫分離mycat是什麽Mycat是一個開源的分布式數據庫系統,但是由於真正的數據庫需要存儲引擎,而Mycat並沒有存儲引擎,所以並不是完全意義的分布式數據庫系統。Mycat是數據庫中間件,就是介於數據庫與應用之間,進行數據處理與交互的中間服務。
Linux的企業-Mysql讀寫分離,組的復制Group-based Replication(2)
mysql讀寫分離 組的復制 基於組的復制(Group-based Replication)是一種被使用在容錯系統中的技術。Replication-group(復制組)是由能夠相互通信的多個服務器(節點)組成的。在通信層,Group replication實現了一系列的機制:比如原子消息(atomic
使用Spring AOP實現MySQL讀寫分離
npr getclass mod rac ava nfa release box port spring aop , mysql 主從配置 實現讀寫分離,下來把自己的配置過程,以及遇到的問題記錄下來,方便下次操作,也希望給一些朋友帶來幫助。mysql主從配置參看:http:
實現MySQL讀寫分離,MySQL性能調優
affect iad list cte 軟件包 密碼 sts 要求 select 實現MySQL讀寫分離 1.1 問題 本案例要求配置2臺MySQL服務器+1臺代理服務器,實現MySQL代理的讀寫分離: 用戶只需要訪問MySQL代理服務器,而實際的SQL查詢、寫入操作交給
6MySQL 主從同步 、 MySQL 讀寫分離 、 MySQL 性能調優
chang 時間 form 變量名 col 最大 rom 驗證 uptime day06一、mysql主從同步 二、數據讀寫分離三、MySQL優化++++++++++++++++++++++++++++++++一、mysql主從同步 1.1 主從同步介紹?從庫服務器自動同
Mysql讀寫分離-Mysql router
post ble -- .rpm https mariadb ogg tcp 實現 原理:MySQL router根據端口來區分讀寫,把連接讀寫端口的所有請求發往master,連接只讀端口的所有請求以輪詢方式發往多個slave,從而實現讀寫分離 主: SQL-Maste
Mysql讀寫分離-amoeba
使用 客戶 cor 刷新 cto query 查詢 runt 刷新數據 轉載自http://www.cnblogs.com/liuyisai/p/6009379.html Amoeba主配置文件($AMOEBA_HOME/conf/amoeba.xml),用來配置Amo