SpringBoot結合Sharding-JDBC實現分庫分表

前言:

今天來聊下 SpringBoot 集成 Sharding-JDBC 實現分庫分表;爲此寫了一個小 Demo,這個Demo是基於SpringBoot,並集成了 Mybatis、Redis、Swagger(生成在線的接口文檔 )、PageHelper(分頁工具) 等,固然絕對也集成了 Sharding-JDBC ;以及設計了 RestFul 風格的接口 ,添加了 單元測試

下面簡單介紹下本文的主線:html

①、首先介紹下Demo的工程目錄,而且介紹下使用的基本環境,如:sql、工程的pom.xml等java

②、而後會着重介紹 SpringBoot 集成 Sharding-JDBC 的過程,及 Sharding-JDBC 基本知識 和 注意事項。node

一、項目信息描述:

完整項目在gitHub,地址: https://github.com/leishen6/S...

若有須要請本身去 giHub 上拉取代碼進行查閱,因爲本人水品有限,若有問題請留言提出,謝謝!mysql

Demo詳解:

一、工程目錄:

二、工程環境:

2.一、pom.xml :
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/>
    </parent>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.7</java.version>

        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>
        <mysql-connector>5.1.39</mysql-connector>
        <fastjson>1.2.41</fastjson>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <!-- Spring Boot Mybatis 依賴 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- MySQL 鏈接驅動依賴 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--druid 鏈接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.16</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson}</version>
        </dependency>

        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- pagehelper分頁工具 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.1.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

        <!-- sharding-jdbc -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

        <!-- hutool 工具類 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-setting</artifactId>
            <version>5.2.4</version>
        </dependency>

    </dependencies>
注意:pom.xml 的內容最好不要改動了,由於若是將裏面的一些 依賴版本變更了 ,可能會致使依賴版本兼容性問題出現,最終致使程序運行失敗。
2.二、sql 環境:

①、數據庫使用的 Mysql,Demo程序運行前須要提早建立好數據庫,因爲使用了分庫分表,因此須要建立兩個庫; 數據庫名:springboot0、springboot1git

②、在 springboot0 數據庫中執行下面的sql語句建立表:github

DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user0
-- ----------------------------
DROP TABLE IF EXISTS `t_user0`;
CREATE TABLE `t_user0` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user1
-- ----------------------------
DROP TABLE IF EXISTS `t_user1`;
CREATE TABLE `t_user1` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user2
-- ----------------------------
DROP TABLE IF EXISTS `t_user2`;
CREATE TABLE `t_user2` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;

③、而後在建立的 springboot1 數據庫中執行sql語句建立表:web

DROP TABLE IF EXISTS `t_user0`;
CREATE TABLE `t_user0` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user1
-- ----------------------------
DROP TABLE IF EXISTS `t_user1`;
CREATE TABLE `t_user1` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user2
-- ----------------------------
DROP TABLE IF EXISTS `t_user2`;
CREATE TABLE `t_user2` (
  `id` int(65) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(10) DEFAULT NULL COMMENT '姓名',
  `age` int(2) DEFAULT NULL COMMENT '年齡',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;
上面的基本信息介紹完了,接下來介紹重頭戲了, Sharding-JDBC 集成之路。嘿嘿 . . . . .

Sharding-JDBC 基本知識:

首先將 Sharding-JDBC 的官網貼出來,也能夠去官網進行詳細瞭解。 shardingsphere 之 Sharding-JDBC

你們若是沒去官網瞭解過的,也能夠經過下面進行了解下喲:redis

一、基本概念:

Sharding-JDBC 定位爲輕量級Java框架,在Java的JDBC層提供的額外服務,因此說它是一款屬於 應用層依賴類中間件 。 它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解爲加強版的JDBC驅動,徹底兼容JDBC和各類ORM框架。算法

應用層依賴類中間件:這類分庫分表中間件的特色就是 和應用強耦合,須要應用顯示依賴相應的jar包。

二、兼容性:

  • 適用於任何基於Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 基於任何第三方的數據庫鏈接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意實現JDBC規範的數據庫。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

三、架構圖:

​ 圖片來源:sharding-JDBC官網spring

四、數據分片:

進行分庫分表時,是繞不開 數據分片 的知識的。

數據分片指按照某個維度將存放在單一數據庫中的數據分散地存放至多個數據庫或表中以達到提高性能瓶頸以及可用性的效果。

數據分片的拆分方式又分爲垂直分片水平分片(最爲經常使用的方式)

4.一、垂直分片:

按照業務拆分的方式稱爲垂直分片,又稱爲縱向拆分,它的核心理念是專庫專用。

例如:原本一個庫由訂單表和用戶表構成,因爲併發量和數據量太大,能夠將這本來的一個庫進行拆分,拆分紅兩個庫,一個訂單庫,裏面只有一個訂單表,一個用戶庫,裏面只有一個用戶表,這樣使用兩個庫就能支持更大的併發量,提高數據庫的併發瓶頸。

缺點:

垂直分片每每須要對架構和設計進行調整。一般來說,是來不及應對互聯網業務需求快速變化的;並且,它也並沒有法真正的解決單點瓶頸。 垂直拆分能夠緩解數據量和訪問量帶來的問題,但沒法根治。

4.二、水平分片:

水平分片又稱爲橫向拆分。 相對於垂直分片,它再也不將數據根據業務邏輯分類,而是經過某個字段(或某幾個字段),根據某種規則將數據分散至多個庫或表中,每一個分片僅包含數據的一部分。

注意:水平分片從理論上突破了單機數據量處理的瓶頸,而且擴展相對自由,是分庫分表的標準解決方案。

例如,本文中實現的分庫分表就是使用的 水平分片 ; 根據用戶表中 name 用戶名字段進行分片;

在新增用戶數據時,首先根據配置的分片策略(分片策略包含分片算法)判斷此用戶名的數據到底新增到哪一個數據庫中,以及哪一個表中。

五、內部執行流程:

核心由 SQL解析 => 執行器優化 => SQL路由 => SQL改寫 => SQL執行 => 結果歸併 的流程組成。

主要介紹下 SQL路由、SQL改寫的概念:

SQL路由:根據解析上下文匹配用戶配置的分片策略,並生成最終的路由路徑;

SQL改寫:將SQL改寫爲在真實數據庫中能夠正確執行的語句。

Sharding-JDBC 集成過程:

一、首先看下 Sharding-JDBC 的配置文件:

下面是Sharding-JDBC 配置文件的內容;

注意:

本工程中的分庫分表是分庫2個,分表3個,分片鍵是 name 字段,分庫分表都是依據name這個分片鍵,

分表只有 t_user 表進行分表;

## 分庫分表 配置: (下面配置的分庫數量、虛擬節點數量等主要是爲了實現一致性hash算法進行分片)

# 分庫數量
sharding.datasource.count=2

# 分庫虛擬節點數量
sharding.datasource.virtual.node.count=360

# 虛擬節點映射到物理節點範圍:例如本文中是根據name名字進行分片的, 因此使用名字的hash值對虛擬節點數取餘;
# 獲得一個0-359的餘數,而後按照餘數所屬的範圍, 若是餘數在0-179範圍則數據分片訪問 springboot0 數據源,
# 若是餘數在180-359範圍,則數據被分片訪問 springboot1 數據源; 下面的分表原理同樣。
sharding.datasource.virtual.node.count.rang=0-179,180-359

# 分表數量
sharding.table.count=3

# 分表虛擬節點數量
sharding.table.virtual.node.count=360

# 虛擬節點映射到物理節點範圍
sharding.table.virtual.node.count.rang=0-119,120-249,250-359


# 實際數據源名字
spring.shardingsphere.datasource.names=springboot0,springboot1

# 數據源
spring.shardingsphere.datasource.springboot0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.springboot0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.springboot0.url=jdbc:mysql://localhost:3306/springboot0?characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.springboot0.username=root
spring.shardingsphere.datasource.springboot0.password=root

spring.shardingsphere.datasource.springboot1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.springboot1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.springboot1.url=jdbc:mysql://localhost:3306/springboot1?characterEncoding=utf-8&useSSL=false
spring.shardingsphere.datasource.springboot1.username=root
spring.shardingsphere.datasource.springboot1.password=root


### 分片策略使用的是: 自定義的分片算法
## 實際的數據節點,符合 groovy 語法; 這裏的{0..1}指的是0到1及其之間的數字,數字有0,1兩個,表明分庫是兩個;
## 而且拼接在 springboot 後面,就構成了上面配置的實際數據源名稱了
spring.shardingsphere.sharding.tables.t_user.actualDataNodes=springboot$->{0..1}.t_user$->{0..2}

## 分片鍵:name字段
spring.shardingsphere.sharding.tables.t_user.databaseStrategy.standard.shardingColumn=name
## 自定義 分庫 算法
spring.shardingsphere.sharding.tables.t_user.databaseStrategy.standard.preciseAlgorithmClassName=com.lyl.algorithm.MyPreciseDBShardingAlgorithm

## 分片鍵:name字段
spring.shardingsphere.sharding.tables.t_user.tableStrategy.standard.shardingColumn=name
## 自定義 分表 算法
spring.shardingsphere.sharding.tables.t_user.tableStrategy.standard.preciseAlgorithmClassName=com.lyl.algorithm.MyPreciseTableShardingAlgorithm


# 不進行分庫分表的數據源指定,使用設置的默認數據源springboot0 ;例如,本文中的 t_role表就不進行
# 分庫分表,那關於 t_role 表的增刪改差都走默認數據源 springboot0
spring.shardingsphere.sharding.default-data-source-name=springboot0
# 打印執行的數據庫以及語句
spring.shardingsphere.props.sql.show=true
若是須要更改分庫數量,或者分表數量的話,那麼也須要對配置文件進行更改;例如:將分庫數量改成3個;

下面這些配置文件內容須要更改:

原配置內容:

sharding.datasource.count=2

sharding.datasource.virtual.node.count.rang=0-179,180-359

spring.shardingsphere.sharding.tables.t_user.actualDataNodes=springboot$->{0..1}.t_user$->{0..2}

改成:

sharding.datasource.count=3

sharding.datasource.virtual.node.count.rang=0-119,120-249,250-359

spring.shardingsphere.sharding.tables.t_user.actualDataNodes=springboot$->{0..2}.t_user$->{0..2}

二、一致性hash算法:

一致性hash算法學習可參考:白話解析:一致性哈希算法 consistent hashing

首先解釋下,sharing-JDBC配置文件中使用的虛擬節點就是爲了實現一致性hash算法;

爲何使用一致性hash算法呢?

由於,使用一致性hash算法是爲了知足後期可能出現的數據庫擴容問題;

在這裏來簡單介紹下,經常使用的分片算法(方式):hash方式,一致性hash(consistent hash),按照數據範圍(range based)。

上面三種分片方式學習可參考:帶着問題學習分佈式系統之數據分片

2.一、介紹一致性hash算法爲何易於擴容呢?

結合下文本,本文是根據name字段進行分片的,使用name用戶名的hash值對虛擬節點數360取餘 ,獲得一個

0-359 的餘數,而後根據餘數匹配配置的虛擬節點範圍進行映射實際物理節點,來獲得實際的數據源節點等。

如圖:

分庫 2個,實際數據源 springboot0、springboot1,虛擬節點數360,虛擬節點範圍 0-179,180-359

進行擴容:(增長一個數據庫)

分庫 3個,實際數據源 springboot0、springboot一、springboot2,虛擬節點數360不變,虛擬節點範圍

0-179,180-269,270-359

如圖,使用一致性hash算法,在擴容時,不會致使總體數據的不可用,只會損失一部分數據;本來分2個庫時,應處於springboot1數據源中的數據,在分庫3時,進行查詢此數據時,會被分片到springboot2中查詢,此時會出現查詢不到的狀況;可是,這也只是損失了一小部分數據,不會致使總體數據出現問題。

三、自定義分片算法:

3.一、自定義分庫實現:

3.二、自定義分表算法:

end,本文結束 . . . . . . . . . . . . . . . .

❤不要忘記留下你學習的足跡 [點贊 + 收藏 + 評論]嘿嘿ヾ

一切看文章不點贊都是「耍流氓」,嘿嘿ヾ(◍°∇°◍)ノ゙!開個玩笑,動一動你的小手,點贊就完事了,你每一個人出一份力量(點贊 + 評論)就會讓更多的學習者加入進來!很是感謝! ̄ω ̄=
相關文章
相關標籤/搜索