<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot+ShardingSphereJDBC實(shí)現(xiàn)讀寫分離!

          共 19161字,需瀏覽 39分鐘

           ·

          2022-07-27 21:44

          往期熱門文章:

          1、不好意思, Maven 該換了!

          2、這是我見過寫得最爛的Controller層代碼,沒有之一!

          3、聊聊接口優(yōu)化的幾種方法

          4、3 步完成 Spring Boot 的日志脫敏

          5、線上MySQL的自增id用盡怎么辦?被面試官干趴下了!

          segmentfault.com/a/1190000040242523


          1 概述

          本文講述了如何使用MyBatisPlus+ShardingSphereJDBC進(jìn)行讀寫分離,以及利用MySQL進(jìn)行一主一從的主從復(fù)制。
          具體步驟包括:
          • MySQL主從復(fù)制環(huán)境準(zhǔn)備(Docker
          • 搭建ShardingShpereJDBC+MyBatisPlus+Druid環(huán)境
          • 測試

          2 環(huán)境

          • OpenJDK 17.0.3
          • Spring Boot 2.7.0
          • MyBatis Plus 3.5.1
          • MyBatis Plus Generator 3.5.2
          • Druid 1.2.10
          • ShardingSphereJDBC 5.1.1
          • MySQL 8.0.29Docker

          3 一些基礎(chǔ)理論

          3.1 讀寫分離

          讀寫分離,顧名思義就是讀和寫分開,更具體來說,就是:
          • 寫操作在主數(shù)據(jù)庫進(jìn)行
          • 讀操作在從數(shù)據(jù)庫進(jìn)行
          使用讀寫分離的根本目的就是為了提高并發(fā)性能,如果讀寫都在同一臺MySQL上實(shí)現(xiàn),相信會不如一臺MySQL寫,另外兩臺MySQL讀這樣的配置性能高。另一方面,在很多時(shí)候都是讀操作的請求要遠(yuǎn)遠(yuǎn)高于寫操作,這樣就顯得讀寫分離非常有必要了。

          3.2 主從復(fù)制

          主從復(fù)制,顧名思義就是把主庫的數(shù)據(jù)復(fù)制到從庫中,因?yàn)樽x寫分離之后,寫操作都在主庫進(jìn)行,但是讀操作是在從庫進(jìn)行的,也就是說,主庫上的數(shù)據(jù)如果不能復(fù)制到從庫中,那么從庫就不會讀到主庫中的數(shù)據(jù)。嚴(yán)格意義上說,讀寫分離并不要求主從復(fù)制,只需要在主庫寫從庫讀即可,但是如果沒有了主從復(fù)制,讀寫分離將失去了它的意義。因此讀寫分離通常與主從復(fù)制配合使用。
          因?yàn)楸臼纠褂玫氖?/span>MySQL,這里就說一下MySQL主從復(fù)制的原理,如下圖所示:

          工作流程如下:
          • 主庫修改數(shù)據(jù)后,將修改日志寫入binlog
          • 從庫的I/O線程讀取主庫的binlog,并拷貝到從庫本地的binlog
          • 從庫本地的binlogSQL線程讀取,執(zhí)行其中的內(nèi)容并同步到從庫中

          3.3 數(shù)據(jù)庫中間件簡介

          數(shù)據(jù)庫中間件可以簡化對讀寫分離以及分庫分表的操作,并隱藏底層實(shí)現(xiàn)細(xì)節(jié),可以像操作單庫單表那樣操作多庫多表,主流的設(shè)計(jì)方案主要有兩種:
          • 服務(wù)端代理:需要獨(dú)立部署一個代理服務(wù),該代理服務(wù)后面管理多個數(shù)據(jù)庫實(shí)例,在應(yīng)用中通過一個數(shù)據(jù)源與該代理服務(wù)器建立連接,由該代理去操作底層數(shù)據(jù)庫,并返回相應(yīng)結(jié)果。優(yōu)點(diǎn)是支持多語言,對業(yè)務(wù)透明,缺點(diǎn)是實(shí)現(xiàn)復(fù)雜,實(shí)現(xiàn)難度大,同時(shí)代理需要確保自身高可用
          • 客戶端代理:在連接池或數(shù)據(jù)庫驅(qū)動上進(jìn)行一層封裝,內(nèi)部與不同的數(shù)據(jù)庫建立連接,并對SQL進(jìn)行必要的操作,比如讀寫分離選擇走主庫還是從庫,分庫分表select后如何聚合結(jié)果。優(yōu)點(diǎn)是實(shí)現(xiàn)簡單,天然去中心化,缺點(diǎn)是支持語言較少,版本升級困難
          一些常見的數(shù)據(jù)庫中間件如下:
          • Cobar:阿里開源的關(guān)系型數(shù)據(jù)庫分布式服務(wù)中間件,已停更
          • DRDS:脫胎于Cobar,全稱分布式關(guān)系型數(shù)據(jù)庫服務(wù)
          • MyCat:開源數(shù)據(jù)庫中間件,目前更新了MyCat2版本
          • AtlasQihoo 360公司Web平臺部基礎(chǔ)架構(gòu)團(tuán)隊(duì)開發(fā)維護(hù)的一個基于MySQL協(xié)議的數(shù)據(jù)中間層項(xiàng)目,同時(shí)還有一個NoSQL的版本,叫Pika
          • tddl:阿里巴巴自主研發(fā)的分布式數(shù)據(jù)庫服務(wù)
          • Sharding-JDBCShardingShpere的一個子產(chǎn)品,一個輕量級Java框架

          4 MySQL主從復(fù)制環(huán)境準(zhǔn)備

          看完了一些基礎(chǔ)理論就可以進(jìn)行動手了,本小節(jié)先準(zhǔn)備好MySQL主從復(fù)制的環(huán)境,基于Docker+MySQL官方文檔搭建。

          4.1 主庫操作

          4.1.1 拉取鏡像并創(chuàng)建容器運(yùn)行

          docker pull mysql
          docker run -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name master mysql
          docker exec -it master /bin/bash
          在主庫中進(jìn)行更新鏡像源,安裝vim以及net-tools的操作:
          cd /etc/apt
          echo deb http://mirrors.aliyun.com/debian/ buster main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib deb http://mirrors.aliyun.com/debian-security buster/updates main deb-src http://mirrors.aliyun.com/debian-security buster/updates main deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib > sources.list
          apt update && apt upgrade
          apt install vim net-tools

          4.1.2 修改配置文件

          vim /etc/mysql/my.cnf
          添加下面兩行數(shù)據(jù):
          [mysqld]
          server-id=1                # 全局唯一,取值[1,2^32-1],默認(rèn)為1
          binlog-do-db=test          # 表示需要復(fù)制的是哪個庫
          修改完成后重啟。

          4.1.3 準(zhǔn)備數(shù)據(jù)源

          CREATE DATABASE test;
          USE test;
          CREATE TABLE user(
              id BIGINT PRIMARY KEY,
              name VARCHAR(30NOT NULL,
          );

          4.1.4 創(chuàng)建一個復(fù)制操作的用戶(可選但推薦)

          注意創(chuàng)建用戶需要加上mysql_native_password,否則會導(dǎo)致從庫一直處于連接狀態(tài):
          CREATE USER 'repl'@'172.17.0.3' IDENTIFIED WITH mysql_native_password BY '123456';
          GRANT REPLICATION slave ON *.* TO 'repl'@'172.17.0.3';
          具體的地址請根據(jù)從庫的地址修改,可以先看后面的從庫配置部分。

          4.1.5 數(shù)據(jù)備份(可選)

          如果原來的主庫中是有數(shù)據(jù)的,那么這部分?jǐn)?shù)據(jù)需要手動同步到從庫中:
          FLUSH TABLES WITH READ LOCK;
          開啟主庫的另一個終端,使用mysqldump導(dǎo)出:
          mysqldump -u root -p --all-databases --master-data > dbdump.db
          導(dǎo)出完成后,解除讀鎖:
          UNLOCK TABLES;

          4.1.6 查看主庫狀態(tài)

          SHOW MASTER STATUS;


          需要把File以及Position記錄下來,后面從庫的配置需要用到。

          4.2 從庫操作

          4.2.1 拉取鏡像并創(chuàng)建容器運(yùn)行

          docker pull mysql
          docker run -itd -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name slave mysql
          docker exec -it slave /bin/bash
          進(jìn)入容器后,像主庫一樣更新源然后安裝vimnet-tools
          cd /etc/apt
          echo deb http://mirrors.aliyun.com/debian/ buster main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib deb http://mirrors.aliyun.com/debian-security buster/updates main deb-src http://mirrors.aliyun.com/debian-security buster/updates main deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib > sources.list
          apt update && apt upgrade
          apt install vim net-tools

          4.2.2 修改配置文件

          vim /etc/mysql/my.cnf
          添加如下兩行:
          [mysqld]
          server-id=2            # 全局唯一,不能與主庫相同
          replicate-do-db=test   # 與主庫相同,表示對該庫進(jìn)行復(fù)制
          修改完成后重啟。

          4.2.3 查看ip地址

          查看從庫的ip地址,用于給主庫設(shè)置同步的用戶:
          ifconfig
          輸出:
          inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255
          那么主庫中用于復(fù)制的用戶就可以是[email protected]

          4.2.4 導(dǎo)入數(shù)據(jù)(可選)

          如果主庫有數(shù)據(jù)可以先導(dǎo)入到從庫:
          mysqldump -u root -p --all-databases < dbdump.db

          4.2.5 準(zhǔn)備數(shù)據(jù)源

          CREATE DATABASE test;
          USE test;
          CREATE TABLE user(
              id BIGINT PRIMARY KEY,
              name VARCHAR(30NOT NULL,
          );

          4.2.6 設(shè)置主庫

          可以使用change master to/change replication source to8.0.23+)命令:
          CHANGE REPLICATION SOURCE TO
          source_host='172.17.0.2',                   # 可以使用ifconfig查看主庫ip
          source_user='repl',                         # 之前主庫創(chuàng)建的用戶
          source_password='123456',                   # 密碼
          source_log_file='binlog.000003',            # 之前在主庫上使用show master status查看的日志文件
          source_log_pos=594;                         # 同樣使用show master status查看

          4.2.7 開啟從庫

          START SLAVE;
          SHOW SLAVE STATUS\G
          新版本(8.0.22+)可使用:
          START REPLICA;
          SHOW REPLICA STATUS\G
          需要IOSQL線程顯示Yes才算成功:

          4.3 測試

          主庫選擇插入一條數(shù)據(jù):
          INSERT INTO user VALUES(1,"name",3);
          然后從庫就能select到了:

          5 搭建Spring Boot環(huán)境

          5.1 新建項(xiàng)目并引入依賴

          新建Spring Boot項(xiàng)目,并引入如下依賴:
          implementation 'com.alibaba:druid:1.2.10'
          implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.1'
          implementation 'org.freemarker:freemarker:2.3.31'
          implementation 'com.baomidou:mybatis-plus-generator:3.5.2'
          implementation 'org.apache.shardingsphere:shardingsphere-jdbc-core-spring-boot-starter:5.1.1'
          Maven版本:
          <dependency>
              <groupId>com.baomidou</groupId>
              <artifactId>mybatis-plus-boot-starter</artifactId>
              <version>3.5.1</version>
          </dependency>
          <dependency>
              <groupId>com.baomidou</groupId>
              <artifactId>mybatis-plus-generator</artifactId>
              <version>3.5.2</version>
          </dependency>
          <dependency>
              <groupId>org.freemarker</groupId>
              <artifactId>freemarker</artifactId>
              <version>2.3.31</version>
          </dependency>
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>druid</artifactId>
              <version>1.2.10</version>
          </dependency>
          <dependency>
              <groupId>org.apache.shardingsphere</groupId>
              <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
              <version>5.1.1</version>
          </dependency>

          5.2 使用生成器

          import com.baomidou.mybatisplus.generator.FastAutoGenerator;
          import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

          public class Generator {
              public static void main(String[] args) {
                  FastAutoGenerator.create("jdbc:mysql://localhost:3306/test""root""123456")
                  .globalConfig(builder ->
                      builder.author("author").outputDir(System.getProperty("user.dir") + "/src/main/java").build())
                  .packageConfig(builder -> 
                      builder.parent("com.example.demo").moduleName("user").build())
                  .strategyConfig(builder -> 
                      builder.addInclude("user").entityBuilder().enableLombok().disableSerialVersionUID().build())
                  .templateEngine(new FreemarkerTemplateEngine())
                  .execute();
              }
          }
          直接運(yùn)行main方法即可生成代碼,配置請根據(jù)個人需要進(jìn)行更改。

          5.3 配置文件

          spring:
            shardingsphere:
              mode:
                type: Memory                                     # 內(nèi)存模式,元數(shù)據(jù)保存在當(dāng)前進(jìn)程中
              datasource:
                names: master,slave                              # 數(shù)據(jù)源名稱,這里有兩個
                master:                                          # 跟上面的數(shù)據(jù)源對應(yīng)
                  type: com.alibaba.druid.pool.DruidDataSource   # 連接池
                  url: jdbc:mysql://127.0.0.1:3306/test          # 連接url
                  username: root
                  password: 123456
                slave:                                           # 跟上面的數(shù)據(jù)源對應(yīng)
                  type: com.alibaba.druid.pool.DruidDataSource
                  url: jdbc:mysql://127.0.0.1:3306/test
                  username: root
                  password: 123456
              rules:
                readwrite-splitting:                             # 讀寫分離規(guī)則
                  data-sources:                                  # 數(shù)據(jù)源配置
                    random:                                      # 這個名字隨便起
                      type: Static                               # 靜態(tài)類型
                      load-balancer-name: round_robin            # 負(fù)載均衡算法名字
                      props:
                        write-data-source-name: master           # 寫數(shù)據(jù)源
                        read-data-source-names: slave            # 讀數(shù)據(jù)源
                  load-balancers:                                # 負(fù)載均衡配置
                    round_robin:                                 # 跟上面負(fù)載均衡算法的名字對應(yīng)
                      type: ROUND_ROBIN                          # 負(fù)載均衡算法
              props:
                sql-show: true                                   # 打印SQL
          因?yàn)榕渲梦募膬?nèi)容比較多,以下進(jìn)行分開說明。

          5.3.1 模式

          spring.shardingsphere.mode.type,模式有三種:
          • Memory:內(nèi)存模式,初始化配置或執(zhí)行SQL等操作均在當(dāng)前進(jìn)程生效
          • Standalone:單機(jī)模式,可以將數(shù)據(jù)源和規(guī)則等元數(shù)據(jù)信息持久化,但是這些元數(shù)據(jù)不會在集群中同步
          • Cluster:集群模式,提供了多個Apache ShardingSphere實(shí)例之間元數(shù)據(jù)共享以及分布式場景下的狀態(tài)協(xié)調(diào)的能力,也提供水平擴(kuò)展以及高可用的能力
          這里使用內(nèi)存模式,如果想將元數(shù)據(jù)等信息持久化,請使用單機(jī)模式,單機(jī)模式需要配置以下屬性:
          • spring.shardingsphere.mode.type=Standalone:設(shè)置單機(jī)模式
          • spring.shardingsphere.mode.repository.type=:持久化倉庫的類型,單機(jī)模式適用類型為File
          • spring.shardingsphere.mode.repository.props.path=:元數(shù)據(jù)存儲路徑,默認(rèn).shardingsphere
          • spring.shardingsphere.mode.overwrite=:是否覆蓋
          而采用集群模式,需要配置以下屬性:
          • spring.shardingsphere.mode.type=Cluster:設(shè)置集群模式
          • spring.shardingsphere.mode.repository.type=:持久化倉庫類型,集群模式支持ZooKeeper以及Etcd持久化
          • spring.shardingsphere.mode.repository.props.namespace=:注冊中心命名空間
          • spring.shardingsphere.mode.repository.props.server-lists=:注冊中心服務(wù)器列表
          • spring.shardingsphere.mode.overwrite=:是否覆蓋
          • spring.shardingsphere.mode.repository.props.<key>=:注冊中心的屬性配置,對于ZooKeeper,可以配置retryIntervalMilliseconds(重試間隔毫秒)、maxRetries(客戶端連接最大重試數(shù))、timeToLiveSeconds(臨時(shí)數(shù)據(jù)存活秒數(shù))、operationTimeoutMilliseconds(客戶端操作超時(shí)毫秒數(shù))、digest(登錄密碼),對于Etcd,可以配置timeToLiveSeconds(臨時(shí)數(shù)據(jù)存活秒數(shù))、connectionTimeout(連接超時(shí)秒數(shù))

          5.3.2 數(shù)據(jù)源配置

          spring.shardingsphere.datasource.names,后面接數(shù)據(jù)源的名稱,使用,分隔,比如此處有兩個數(shù)據(jù)源:
          • master
          • slave
          然后每個數(shù)據(jù)源可以配置:
          • type:數(shù)據(jù)庫連接池類型,這里使用的是Druid
          • username:用戶名
          • password:密碼
          • jdbc-url:連接url,注意,對于此處使用的Druid連接池,需要使用url而不是jdbc-url

          5.3.3 讀寫分離規(guī)則配置

          spring.shardingsphere.rules.readwrite-splitting,需要配置其中的數(shù)據(jù)源以及負(fù)載均衡類型:
          • spring.shardingsphere.rules.readwrite-splitting.data-sources
          • spring.shardingsphere.rules.readwrite-splitting.load-balancers
          5.3.3.1 數(shù)據(jù)源配置
          數(shù)據(jù)源配置首先需要添加一個數(shù)據(jù)源的名字,隨便起一個,比如這里是random,然后需要配置三個屬性:
          • spring.shardingsphere.rules.readwrite-splitting.data-sources.random.type:讀寫分離的類型,可選值為StaticDynamic,這里選擇Static,如果選擇Dynamic,也就是動態(tài)數(shù)據(jù)源,請配合dynamic-datasource-spring-boot-starter使用
          • spring.shardingsphere.rules.readwrite-splitting.data-sources.random.props.write-data-source-name:寫數(shù)據(jù)源
          • spring.shardingsphere.rules.readwrite-splitting.data-sources.random.props.read-data-source-name:讀數(shù)據(jù)源
          • spring.shardingsphere.rules.readwrite-splitting.data-sources.random.load-balancer-name:負(fù)載均衡算法的名稱,這里寫的是round_robin
          5.3.3.2 負(fù)載均衡配置
          負(fù)載均衡配置需要與上面的spring.shardingsphere.rules.readwrite-splitting.data-sources.random.load-balancer-name屬性對應(yīng),比如這里是round_robin,那么需要配置的就是spring.shardingsphere.rules.readwrite-splitting.load-balancers.round_robin。然后下一步就是配置具體的負(fù)載均衡算法。
          內(nèi)置的負(fù)載均衡算法有三個:
          • 輪詢算法:ROUND_ROBIN,配置type=ROUND_ROBIN即可,也就是spring.shardingsphere.rules.readwrite-splitting.load-balancers.round_robin.type=ROUND_ROBIN
          • 隨機(jī)訪問算法:RANDOM,配置type=RANDOM
          • 權(quán)重訪問算法:WEIGHT,配置type=WEIGHT,同時(shí)需要配置props,在其中配置各個讀節(jié)點(diǎn)的權(quán)重

          5.3.4 屬性配置

          屬性的話這里只配置了一個spring.shardingsphere.props.sql-show=true,也就是打印SQL,其他支持的屬性有:
          • spring.shardingsphere.props.sql-simple:是否打印簡單風(fēng)格的SQL,默認(rèn)為false
          • spring.shardingsphere.props.kernel-exector-size:設(shè)置任務(wù)處理線程池大小,默認(rèn)為infinite
          • spring.shardingsphere.props.max-connections-size-per-query:每次查詢所能使用的最多數(shù)據(jù)庫連接數(shù),默認(rèn)為1
          • spring.shardingsphere.props.check-table-metadata-enabled:啟動時(shí)是否檢查分片元數(shù)據(jù)的一致性,默認(rèn)為false
          • spring.shardingsphere.props.check-duplicate-table-enabled:啟動時(shí)是否檢查重復(fù)表,默認(rèn)為false
          • spring.shardingsphere.props.sql-federation-enabled:是否開啟聯(lián)邦查詢,默認(rèn)為false

          5.4 準(zhǔn)備Controller

          @RestController
          @RequestMapping("/user")
          @RequiredArgsConstructor(onConstructor = @__(@Autowired))
          public class UserController {
              private final UserServiceImpl userService;

              @GetMapping("/select")
              public User select() {
                  return userService.getById(1);
              }

              @GetMapping("/insert")
              public boolean insert() {
                  return userService.saveOrUpdate(User.builder().id(3L).name("name3").build());
              }
          }

          6 測試

          訪問http://localhost:8080/user/insert,可以看到寫操作在主庫進(jìn)行:
          訪問http://localhost:8080/user/select,可以看到讀操作在從庫進(jìn)行:
          這樣讀寫分離就算是完成了。
          往期熱門文章:

          1、線上MySQL的自增id用盡怎么辦?被面試官干趴下了!
          2、計(jì)算機(jī)專業(yè)會不會成為下一個土木?
          3、xxl-job驚艷的設(shè)計(jì),怎能叫人不愛
          4、ArrayList#subList這四個坑,一不小心就中招
          5、面試官:大量請求 Redis 不存在的數(shù)據(jù),從而影響數(shù)據(jù)庫,該如何解決?
          6、MySQL 暴跌!
          7、超越 Xshell!號稱下一代 Terminal 終端神器,用完愛不釋手!
          8、IDEA 官宣全新默認(rèn) UI,太震撼了!!
          9、讓你直呼「臥槽」的 GitHub 項(xiàng)目!
          10、Kafka又笨又重,為啥不選Redis?

          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人自拍视频在线 | 特级毛片www | 欧美色视频在线 | 亚洲第一页国产 | 丁香五月综合在线 |