一、ShardingSphere簡介
Apache ShardingSphere 是一套開源的分布式數(shù)據(jù)庫解決方案組成的生態(tài)圈,它由 JDBC、Proxy 和 Sidecar(規(guī)劃中)這 3 款既能夠獨(dú)立部署,又支持混合部署配合使用的產(chǎn)品組成。 它們均提供標(biāo)準(zhǔn)化的數(shù)據(jù)水平擴(kuò)展、分布式事務(wù)和分布式治理等功能,可適用于如 Java 同構(gòu)、異構(gòu)語言、云原生等各種多樣化的應(yīng)用場景。
以下是Sharding Sphere在Github上的star數(shù):

Apache ShardingSphere 旨在充分合理地在分布式的場景下利用關(guān)系型數(shù)據(jù)庫的計(jì)算和存儲能力,而并非實(shí)現(xiàn)一個全新的關(guān)系型數(shù)據(jù)庫。 關(guān)系型數(shù)據(jù)庫當(dāng)今依然占有巨大市場份額,是企業(yè)核心系統(tǒng)的基石,未來也難于撼動,我們更加注重在原有基礎(chǔ)上提供增量,而非顛覆。

Apache ShardingSphere 5.x 版本開始致力于可插拔架構(gòu),項(xiàng)目的功能組件能夠靈活的以可插拔的方式進(jìn)行擴(kuò)展。 目前,數(shù)據(jù)分片、讀寫分離、數(shù)據(jù)加密、影子庫壓測等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 與協(xié)議的支持,均通過插件的方式織入項(xiàng)目。 開發(fā)者能夠像使用積木一樣定制屬于自己的獨(dú)特系統(tǒng)。Apache ShardingSphere 目前已提供數(shù)十個 SPI 作為系統(tǒng)的擴(kuò)展點(diǎn),仍在不斷增加中。
Sharding-JDBC
定位為輕量級 Java 框架,在 Java 的 JDBC 層提供的額外服務(wù)。 它使用客戶端直連數(shù)據(jù)庫,以 jar 包形式提供服務(wù),無需額外部署和依賴,可理解為增強(qiáng)版的 JDBC 驅(qū)動,完全兼容 JDBC 和各種 ORM 框架。

適用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
支持任何第三方的數(shù)據(jù)庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
支持任意實(shí)現(xiàn) JDBC 規(guī)范的數(shù)據(jù)庫,目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 標(biāo)準(zhǔn)的數(shù)據(jù)庫。
Sharding-Proxy
定位為透明化的數(shù)據(jù)庫代理端,提供封裝了數(shù)據(jù)庫二進(jìn)制協(xié)議的服務(wù)端版本,用于完成對異構(gòu)語言的支持。 目前提供 MySQL 和 PostgreSQL 版本,它可以使用任何兼容 MySQL/PostgreSQL 協(xié)議的訪問客戶端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作數(shù)據(jù),對 DBA 更加友好。

向應(yīng)用程序完全透明,可直接當(dāng)做 MySQL/PostgreSQL 使用。
適用于任何兼容 MySQL/PostgreSQL 協(xié)議的的客戶端。
二、ShardingJDBC實(shí)戰(zhàn)
2.1 基礎(chǔ)環(huán)境搭建
springboot整合mybatis-plus為例,添加依賴
<!--mybatis-plus依賴-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--sharding-jdbc依賴-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<!--分布式事務(wù)XA支持-->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>4.1.1</version>
</dependency>
其中,sharding-transaction-xa-core是分布式事務(wù)的支持,如果不需要使用XA做分布式事務(wù),則可以不用添加。
數(shù)據(jù)庫

2.1.1 數(shù)據(jù)源配置
#打印sql
spring.shardingsphere.props.sql.show=true
#datasource
spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/heima1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/heima2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456
spring.shardingsphere.datasource.names指定當(dāng)前的數(shù)據(jù)源名稱,比如這里的ds0、ds1就是配置了兩個數(shù)據(jù)源。然后接下來分別對兩個數(shù)據(jù)源配置如下幾個內(nèi)容
-
type數(shù)據(jù)庫連接池 -
driver-class-name數(shù)據(jù)庫驅(qū)動 -
jdbc-url數(shù)據(jù)庫連接地址 -
username賬號名稱 -
password密碼
2.1.2 分庫配置
#sharding-database
spring.shardingsphere.sharding.tables.position.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.position.database-strategy.inline.algorithm-expression=ds$->{id % 2}
這里提到一個關(guān)鍵詞inline行表達(dá)式,行表達(dá)式的使用非常直觀,只需要在配置中使用 ${ expression } 或$->{ expression }標(biāo)識行表達(dá)式即可。 行表達(dá)式的內(nèi)容使用的是 Groovy 的語法,Groovy 能夠支持的所有操作,行表達(dá)式均能夠支持。例如:
-
${begin..end}表示范圍區(qū)間 -
${[unit1, unit2, unit_x]}表示枚舉值
所以上述sharding-column=id指的是指定當(dāng)前分庫時需要依賴的分片鍵是id,algorithm-expression=ds$->{id % 2}指的是分片算法是將id取模之后,和ds進(jìn)行拼接:
比如查詢的id如果是1000,1000在對2取模之后會變成ds0,然后sql語句就會去ds0這個數(shù)據(jù)源中執(zhí)行。
2.1.3 實(shí)體類定義
package com.brianxia.shardingjdbcmybatis.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@TableName("position")
@Data
public class Position implements Serializable {
@TableId(value = "id",type = IdType.INPUT)
private Long id;
private String name;
private String salary;
private String city;
}
2.1.4 mapper接口添加
package com.brianxia.shardingjdbcmybatis.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.brianxia.shardingjdbcmybatis.entity.BOrder;
import com.brianxia.shardingjdbcmybatis.entity.Position;
import org.apache.ibatis.annotations.Mapper;
/**
* @author brianxia
* @version 1.0
* @date 2021/5/25 15:41
*/
@Mapper
public interface PositionMapper extends BaseMapper<Position> {
}
三、 測試
package com.brianxia.shardingjdbcmybatis;
import com.brianxia.shardingjdbcmybatis.entity.Position;
import com.brianxia.shardingjdbcmybatis.mapper.PositionMapper;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author brianxia
* @version 1.0
* @date 2021/5/27 18:45
*/
@SpringBootTest
public class BaseTest {
@Autowired
private PositionMapper positionMapper;
@Test
public void add(){
for (long i = 0; i < 100; i++) {
Position position = new Position();
position.setId(i);
positionMapper.insert(position);
}
}
}
首先使用自定義的id進(jìn)行數(shù)據(jù)庫的插入,執(zhí)行日志:
2021-05-27 18:49:42.394 INFO 21560 --- [ main] ShardingSphere-SQL : Logic SQL: INSERT INTO position ( id ) VALUES ( ? )
2021-05-27 18:49:42.394 INFO 21560 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@20c3b34b, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@ff21443), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@ff21443, columnNames=[id], insertValueContexts=[InsertValueContext(parametersCount=1, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=40, stopIndex=40, parameterMarkerIndex=0)], parameters=[97])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=id, generated=false, generatedValues=[97])])
2021-05-27 18:49:42.394 INFO 21560 --- [ main] ShardingSphere-SQL : Actual SQL: ds1 ::: INSERT INTO position ( id ) VALUES (?) ::: [97]
2021-05-27 18:49:42.398 INFO 21560 --- [ main] ShardingSphere-SQL : Logic SQL: INSERT INTO position ( id ) VALUES ( ? )
2021-05-27 18:49:42.398 INFO 21560 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@20c3b34b, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6253e59a), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@6253e59a, columnNames=[id], insertValueContexts=[InsertValueContext(parametersCount=1, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=40, stopIndex=40, parameterMarkerIndex=0)], parameters=[98])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=id, generated=false, generatedValues=[98])])
2021-05-27 18:49:42.398 INFO 21560 --- [ main] ShardingSphere-SQL : Actual SQL: ds0 ::: INSERT INTO position ( id ) VALUES (?) ::: [98]
2021-05-27 18:49:42.402 INFO 21560 --- [ main] ShardingSphere-SQL : Logic SQL: INSERT INTO position ( id ) VALUES ( ? )
2021-05-27 18:49:42.402 INFO 21560 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@20c3b34b, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@12f8682a), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@12f8682a, columnNames=[id], insertValueContexts=[InsertValueContext(parametersCount=1, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=40, stopIndex=40, parameterMarkerIndex=0)], parameters=[99])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=id, generated=false, generatedValues=[99])])
2021-05-27 18:49:42.402 INFO 21560 --- [ main] ShardingSphere-SQL : Actual SQL: ds1 ::: INSERT INTO position ( id ) VALUES (?) ::: [99]
可以看到,奇數(shù)的id已經(jīng)被送到了ds1庫中,偶數(shù)的id被送到了dis0庫中。

四、 總結(jié)
通過簡單的配置ShardingSphere已經(jīng)完成了分庫操作,下一小節(jié)中我們會使用ShardingSphere進(jìn)行分庫+分表,同時解決主鍵ID生成的問題。