Sharding-JDBC4.0學習與實踐(一)

 

 

一、概述

Sharding-JDBC定位爲輕量級Java框架,在Java的JDBC層提供的額外服務。 它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解爲增強版的JDBC驅動,完全兼容JDBC和各種ORM框架。

適用於任何基於JDBCORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC

支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。

支持任意實現JDBC規範的數據庫。目前支持MySQLOracleSQLServerPostgreSQL以及任何遵循SQL92標準的數據庫。

 

 

二、功能列表

1. 數據分片

分庫 & 分表

讀寫分離

分片策略定製化

無中心化分佈式主鍵

2. 分佈式事務

標準化事務接口

XA強一致事務

柔性事務

3. 數據庫治理

配置動態化

編排 & 治理

數據脫敏

可視化鏈路追蹤

彈性伸縮(規劃中)

三、項目狀態

四、數據分片

背景

 傳統的將數據集中存儲至單一數據節點的解決方案,在性能、可用性和運維成本這三方面已經難於滿足互聯網的海量數據場景。

  1. 從性能方面來說,由於關係型數據庫大多采用B+樹類型的索引,在數據量超過閾值的情況下,索引深度的增加也將使得磁盤訪問的IO次數增加,進而導致查詢性能的下降;同時,高併發訪問請求也使得集中式數據庫成爲系統的最大瓶頸。
  2. 從可用性的方面來講,服務化的無狀態型,能夠達到較小成本的隨意擴容,這必然導致系統的最終壓力都落在數據庫之上。而單一的數據節點,或者簡單的主從架構,已經越來越難以承擔。數據庫的可用性,已成爲整個系統的關鍵。
  3. 從運維成本方面考慮,當一個數據庫實例中的數據達到閾值以上,對於DBA的運維壓力就會增大。數據備份和恢復的時間成本都將隨着數據量的大小而愈發不可控。一般來講,單一數據庫實例的數據的閾值在1TB之內,是比較合理的範圍。

NoSQL的不足

    在傳統的關係型數據庫無法滿足互聯網場景需要的情況下,將數據存儲至原生支持分佈式的NoSQL的嘗試越來越多。 但NoSQLSQL的不兼容性以及生態圈的不完善,使得它們在與關係型數據庫的博弈中始終無法完成致命一擊,而關係型數據庫的地位卻依然不可撼動。

數據分片

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

數據分片的有效手段是對關係型數據庫進行分庫和分表

分庫和分表均可以有效的避免由數據量超過可承受閾值而產生的查詢瓶頸。 除此之外,分庫還能夠用於有效的分散對數據庫單點的訪問量;分表雖然無法緩解數據庫壓力,但卻能夠提供儘量將分佈式事務轉化爲本地事務的可能,一旦涉及到跨庫的更新操作,分佈式事務往往會使問題變得複雜。 使用多主多從的分片方式,可以有效的避免數據單點,從而提升數據架構的可用性。

通過分庫和分表進行數據的拆分來使得各個表的數據量保持在閾值以下,以及對流量進行疏導應對高訪問量,是應對高併發和海量數據系統的有效手段。 數據分片的拆分方式又分爲垂直分片水平分片

垂直分片

按照業務拆分的方式稱爲垂直分片,又稱爲縱向拆分,它的核心理念是專庫專用。 在拆分之前,一個數據庫由多個數據表構成,每個表對應着不同的業務。而拆分之後,則是按照業務將表進行歸類,分佈到不同的數據庫中,從而將壓力分散至不同的數據庫。 下圖展示了根據業務需要,將用戶表和訂單表垂直分片到不同的數據庫的方案。

垂直分片往往需要對架構和設計進行調整。通常來講,是來不及應對互聯網業務需求快速變化的;而且,它也並無法真正的解決單點瓶頸。垂直拆分可以緩解數據量和訪問量帶來的問題,但無法根治。如果垂直拆分之後,表中的數據量依然超過單節點所能承載的閾值,則需要水平分片來進一步處理。

水平分片

水平分片又稱爲橫向拆分。 相對於垂直分片,它不再將數據根據業務邏輯分類,而是通過某個字段(或某幾個字段),根據某種規則將數據分散至多個庫或表中,每個分片僅包含數據的一部分。 例如:根據主鍵分片,偶數主鍵的記錄放入0庫(或表),奇數主鍵的記錄放入1庫(或表),如下圖所示。

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

挑戰

雖然數據分片解決了性能、可用性以及單點備份恢復等問題,但分佈式的架構在獲得了收益的同時,也引入了新的問題。

  1. 面對如此散亂的分庫分表之後的數據,應用開發工程師和數據庫管理員對數據庫的操作變得異常繁重就是其中的重要挑戰之一。他們需要知道數據需要從哪個具體的數據庫的分表中獲取。
  2. 另一個挑戰則是,能夠正確的運行在單節點數據庫中的SQL,在分片之後的數據庫中並不一定能夠正確運行。例如,分表導致表名稱的修改,或者分頁、排序、聚合分組等操作的不正確處理。
  3. 跨庫事務也是分佈式的數據庫集羣要面對的棘手事情。

合理採用分表,可以在降低單表數據量的情況下,儘量使用本地事務,善於使用同庫不同表可有效避免分佈式事務帶來的麻煩。

在不能避免跨庫事務的場景,有些業務仍然需要保持事務的一致性。 而基於XA的分佈式事務由於在併發度高的場景中性能無法滿足需要,並未被互聯網巨頭大規模使用,他們大多采用最終一致性的柔性事務代替強一致事務。

目標

儘量透明化分庫分表所帶來的影響,讓使用方儘量像使用一個數據庫一樣使用水平分片之後的數據庫集羣,是ShardingSphere數據分片模塊的主要設計目標。

核心概念

SQL

  1. 邏輯表

水平拆分後數據庫表的邏輯總稱。例:訂單數據根據主鍵尾數拆分爲10張表,分別是t_order_0t_order_9,他們的邏輯表名爲t_order

   2. 真實表(物理表)

在分片的數據庫中真實存在的物理表。即上個示例中的t_order_0t_order_9

    3. 數據節點

數據分片的最小單元。由數據源名稱和數據表組成,例:ds_0.t_order_0

    4.  綁定表

指分片規則一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,則此兩張表互爲綁定表關係。綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,關聯查詢效率將大大提升。

舉例說明,如果SQL爲:

SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

在不配置綁定表關係時,假設分片鍵order_id將數值10路由至第0片,將數值11路由至第1片,那麼路由後的SQL應該爲4條,它們呈現爲笛卡爾積:

SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

在配置綁定表關係後,路由的SQL應該爲2條:

SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);

其中t_order在FROM的最左側,ShardingSphere將會以它作爲整個綁定表的主表。 所有路由計算將會只使用主表的策略,那麼t_order_item表的分片計算將會使用t_order的條件。故綁定表之間的分區鍵要完全相同。

5. 廣播表

指所有的分片數據源中都存在的表。它的表結構和表中的數據在每個數據庫中均完全一致。適用於數據量不大且需要與其他有海量數據的表進行關聯查詢的場景,例如:字典表。

分片

  1. 分片鍵

用於分片的數據庫字段,是將數據庫(表)水平拆分的關鍵字段。例:將訂單表中的訂單主鍵的尾數取模分片,則訂單主鍵爲分片字段。 SQL中如果無分片字段,將執行全路由,性能較差。 除了對單分片字段的支持,ShardingSphere也支持根據多個字段進行分片。

    2.分片算法

通過分片算法將數據分片,支持通過=>=<=><BETWEENIN分片。分片算法需要應用方開發者自行實現,可實現的靈活度非常高。

目前提供4種分片算法。由於分片算法和業務實現緊密相關,因此並未提供內置分片算法,而是通過分片策略將各種場景提煉出來,提供更高層級的抽象,並提供接口讓應用開發者自行實現分片算法。

    1)精確分片算法

對應PreciseShardingAlgorithm,用於處理使用單一鍵作爲分片鍵,並用=與IN進行分片的場景。需要配合StandardShardingStrategy使用。

    2)範圍分片算法

對應RangeShardingAlgorithm,用於處理使用單一鍵作爲分片鍵的BETWEEN AND、>、<、>=、<=進行分片的場景。需要配合StandardShardingStrategy使用。

    3)複合分片算法

對應ComplexKeysShardingAlgorithm,用於處理使用多個鍵作爲分片鍵進行分片的場景,包含多個分片鍵的邏輯較爲複雜,需要應用開發者自行處理其中的複雜度。需要配合ComplexShardingStrategy使用。

   4)Hint分片算法

       對應HintShardingAlgorithm,用於處理使用Hint行分片的場景。需要配合HintShardingStrategy使用。

  3. 分片策略

       包含分片鍵和分片算法,由於分片算法的獨立性,將其單獨抽離。真正可用於分片操作的是分片鍵 + 分片算法,也就是分片策略。目前提供5種分片策略。

        1)標準分片策略

       對應StandardShardingStrategy。提供對SQL語句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。

       PreciseShardingAlgorithm是必選的,用於處理=和IN的分片。RangeShardingAlgorithm是可選的,用於處理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。  

          2)複合分片策略

       對應ComplexShardingStrategy。複合分片策略。提供對SQL語句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片鍵,由於多分片鍵之間的關係複雜,因此並未進行過多的封裝,而是直接將分片鍵值組合以及分片操作符傳給分片算法,完全由應用開發者實現,提供最大的靈活度。

         3)行表達式分片策略

       對應InlineShardingStrategy。使用Groovy的表達式,提供對SQL語句中的=和IN的分片操作支持,只支持單分片鍵。對於簡單的分片算法,可以通過簡單的配置使用,從而避免繁瑣的Java代碼開發,如: t_user_$->{u_id % 8} 表示t_user表根據u_id模8,而分成8張表,表名稱爲t_user_0t_user_7

           4)Hint分片策略

       對應HintShardingStrategy。通過Hint指定分片值而非從SQL中提取分片值的方式進行分片的策略。

            5)不分片策略

       對應NoneShardingStrategy。不進行分片的策略。

SQL Hint

       對於分片字段非SQL決定,而由其他外置條件決定的場景,可使用SQL Hint靈活的注入分片字段。例:內部系統,按照員工登錄主鍵分庫,而數據庫中並無此字段。SQL Hint支持通過Java API和SQL註釋(待實現)兩種方式使用。

 

五、數據分片試驗

shardingsphere的官網https://shardingsphere.apache.org/document/current/cn/overview/文字描述含混不清,網上的帖子也比較陳舊。試驗它的配置,連蒙帶猜幹了一下午,終於跑通了一個例子。記下來爲初學者填一些坑。

 

用下列組件完成實例:

MySQL8.0.18

SpringBoot2.1.2

MyBatis3.4.2

Sharding-JDBC4.0.0

  1. 準備分片後的數據庫和表

init.sql文件

以下SQL寫在init.sql文件中,用於生成數據庫表。

CREATE DATABASE ds0;
USE ds0;


DROP TABLE IF EXISTS t_order0;
CREATE TABLE t_order0 (
 
order_id bigint(20) NOT NULL,
 
user_id bigint(20) NOT NULL,
 
order_name varchar(100) COLLATE utf8_bin NOT NULL,
 
PRIMARY KEY (order_id)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS t_order1;
CREATE TABLE t_order1 (
 
order_id bigint(20) NOT NULL,
 
user_id bigint(20) NOT NULL,
 
order_name varchar(100) COLLATE utf8_bin NOT NULL,
 
PRIMARY KEY (order_id)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE DATABASE ds1;
USE ds1;


DROP TABLE IF EXISTS t_order0;
CREATE TABLE t_order0 (
 
order_id bigint(20) NOT NULL,
 
user_id bigint(20) NOT NULL,
 
order_name varchar(100) COLLATE utf8_bin NOT NULL,
 
PRIMARY KEY (order_id)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS t_order1;
CREATE TABLE t_order1 (
 
order_id bigint(20) NOT NULL,
 
user_id bigint(20) NOT NULL,
 
order_name varchar(100) COLLATE utf8_bin NOT NULL,
 
PRIMARY KEY (order_id)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

 

在MySQL WorkBench中連接本地MySQL數據庫後執行這些SQL語句。最後得到如下庫表:

t_order{0,1}的四個表的表結構完全相同。

  1. 創建Maven工程

在IDEA中創建Maven工程。

pom.xml文件

pom.xml內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.harry</groupId>
    <artifactId>springbootShardingJDBC</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- Inherit defaults from Spring Boot -->
   
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- Add typical dependencies for a web application -->
   
<dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.2.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>

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

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

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
       
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.7.0</version>
        </dependency>

    </dependencies>

    <!-- Package as an executable jar -->
   
<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 如果不設置fork,那麼不會restart,devtools熱部署不會起作用-->
                   
<fork>true</fork>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>

            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

工程結構

工程結構如下:

基本上是最簡單的結構。

  1. 生成Model, DAO,和Mapper.xml文件

generatorConfig.xml文件

編寫generatorConfig.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 數據庫驅動:選擇你的本地硬盤上面的數據庫驅動包-->
   
<classPathEntry  location="D:\Java\apache-maven-3.6.3\repository\mysql\mysql-connector-java\8.0.13\mysql-connector-java-8.0.13.jar"/>
    <context id="DB2Tables"  targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自動生成的註釋 true:是 false: -->
           
<property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--數據庫鏈接URL,用戶名、密碼 -->
       
<jdbcConnection
               
driverClass="com.mysql.cj.jdbc.Driver"
               
connectionURL="jdbc:mysql://127.0.0.1:3306/ds0?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT&amp;allowPublicKeyRetrieval=true"
               
userId="root"
               
password="root"/>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成模型的包名和位置-->
       
<javaModelGenerator targetPackage="com.harry.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置-->
       
<sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置-->
       
<javaClientGenerator type="XMLMAPPER" targetPackage="com.harry.dao" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名-->
       
<table tableName="t_order0" domainObjectName="Order" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    </context>
</generatorConfiguration>

 

運行Maven窗口裏的

它會在你設置的目錄裏自動生成model,daomapper.xml文件。

這樣我們就基本上不用怎麼寫代碼了。

Order.java文件

Order.java的內容:

package com.harry.model;

public class Order {
   
private Long orderId;

   
private Long userId;

   
private String orderName;

   
public Order(Long orderId,Long userId,String orderName){
       
this.orderId = orderId;
       
this.userId = userId;
       
this.orderName = orderName;
    }

   
public Long getOrderId() {
       
return orderId;
    }

   
public void setOrderId(Long orderId) {
       
this.orderId = orderId;
    }

   
public Long getUserId() {
       
return userId;
    }

   
public void setUserId(Long userId) {
       
this.userId = userId;
    }

   
public String getOrderName() {
       
return orderName;
    }

   
public void setOrderName(String orderName) {
       
this.orderName = orderName == null ? null : orderName.trim();
    }
}

OrderMapper.java文件

OrderMapper.java的內容:

package com.harry.dao;

import com.harry.model.Order;

public interface OrderMapper {
   
int deleteByPrimaryKey(Long orderId);

   
int insert(Order record);

   
int insertSelective(Order record);

    Order selectByPrimaryKey(Long orderId);

   
int updateByPrimaryKeySelective(Order record);

   
int updateByPrimaryKey(Order record);
}

OrderMapper.xml文件

OrderMapper.xml的內容:

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.harry.dao.OrderMapper">
  <resultMap id="BaseResultMap" type="com.harry.model.Order">
    <id column="order_id" jdbcType="BIGINT" property="orderId" />
    <result column="user_id" jdbcType="BIGINT" property="userId" />
    <result column="order_name" jdbcType="VARCHAR" property="orderName" />
  </resultMap>
  <sql id="Base_Column_List">
    order_id, user_id, order_name
  </
sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select
    <
include refid="Base_Column_List" />
    from t_order
    where order_id = #{orderId,jdbcType=BIGINT}
  </
select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from t_order
    where order_id = #{orderId,jdbcType=BIGINT}
  </
delete>
  <insert id="insert" parameterType="com.harry.model.Order">
    insert into t_order (order_id, user_id, order_name
      )
    values (#{orderId,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{orderName,jdbcType=VARCHAR}
      )
  </
insert>
  <insert id="insertSelective" parameterType="com.harry.model.Order">
    insert into t_order
    <
trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="orderId != null">
        order_id,
      </
if>
      <if test="userId != null">
        user_id,
      </
if>
      <if test="orderName != null">
        order_name,
      </
if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="orderId != null">
        #{orderId,jdbcType=BIGINT},
      </
if>
      <if test="userId != null">
        #{userId,jdbcType=BIGINT},
      </
if>
      <if test="orderName != null">
        #{orderName,jdbcType=VARCHAR},
      </
if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.harry.model.Order">
    update t_order
    <
set>
      <if test="userId != null">
        user_id = #{userId,jdbcType=BIGINT},
      </
if>
      <if test="orderName != null">
        order_name = #{orderName,jdbcType=VARCHAR},
      </
if>
    </set>
    where order_id = #{orderId,jdbcType=BIGINT}
  </
update>
  <update id="updateByPrimaryKey" parameterType="com.harry.model.Order">
    update t_order
    set user_id = #{userId,jdbcType=BIGINT},
      order_name = #{orderName,jdbcType=VARCHAR}
    where order_id = #{orderId,jdbcType=BIGINT}
  </
update>

</mapper>

 

Application.java文件

Application.java的內容:

package com.harry;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan
("com.harry.dao")
public class Application {

   
public static void main(String[] args) {
        SpringApplication.run(Application.
class,args);
    }
}

application.properties文件

分佈分表的策略和方法都定義在application.properties中。這裏我們採用了最簡單的inline的方法。application.properties的內容如下:


mybatis.mapperLocations=classpath:mapping/*.xml

# Sharding-JDBC配置項
#數據源名稱,多數據源以逗號分隔
spring.shardingsphere.datasource.names=ds0,ds1
#數據庫連接池類名稱
spring.shardingsphere.datasource.ds0.type=org.apache.commons.dbcp2.BasicDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://127.0.0.1:3306/ds0?useUnicode\=true&characterEncoding\=utf-8&useSSL\=false&serverTimezone\=GMT&allowPublicKeyRetrieval\=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root

spring.shardingsphere.datasource.ds1.type=org.apache.commons.dbcp2.BasicDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://127.0.0.1:3306/ds1?useUnicode\=true&characterEncoding\=utf-8&useSSL\=false&serverTimezone\=GMT&allowPublicKeyRetrieval\=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root

#默認數據庫分片策略,即分庫策略,爲inline
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#分庫算法
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2}

# t_order<logic-table-name>
# actual-data-nodes
由數據源名.表名組成,以小數點分隔。多個表以逗號分隔,支持inline表達式。
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order$->{0..1}
# 分表策略爲inline
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# 分表算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order$->{order_id % 2}

 

測試類

下面是我們的測試類。

package com.harry.test;

import com.harry.Application;
import com.harry.dao.OrderMapper;
import com.harry.model.Order;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class OrderTest {

   
@Resource
   
private OrderMapper orderMapper;

   
@Test
   
public void testAddOrder(){
        Order order0_0 =
new Order(0L,0L,"order0_0");
        Order order0_1 =
new Order(1L,0L,"order0_1");
        Order order1_2 =
new Order(2L,1L,"order1_2");
        Order order1_3 =
new Order(3L,1L,"order1_3");
       
orderMapper.insert(order0_0);
       
orderMapper.insert(order0_1);
       
orderMapper.insert(order1_2);
       
orderMapper.insert(order1_3);
    }
}

 

  1. 執行測試類

執行測試類,它將按照預定義的分庫分表的規則(按user_id % 2分庫,按order_id % 2分表)向ds0.t_order0, ds0.t_order1, ds1.t_order0, ds1.t_order1四個表中分別插入一條數據。

執行結果

          

              

 

 

有了這個例子,再試驗Sharding-JDBC的其他功能就比較方便快捷了。

 

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