ShardingJDBC

概述

ShardingJDBC是一个开源的基于 Java 的分库分表中间件,用于处理关系型数据库的分片操作(供了水平分片垂直分片两种分片方式)。它可以将数据按照某种规则分散存储在不同的数据库中,从而有效地解决了单一数据库在处理大量数据时的性能瓶颈问题。

ShardingJDBC定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。

image-20240511204847085

ShardingJDBC是以SDK的方式集成在项目中,还有一种方式是以独立服务的中间件模式(例如ShardingProxy、MyCat),两者的主要区别为:

image-20240512113354429

读写分离

读写分离是指在数据库集群中将读操作写操作分发到不同的节点上执行。通常情况下,写操作的频率相对较低,但是对数据的一致性要求较高,而读操作的频率较高,但是对数据的一致性要求较低。通过将读操作和写操作分离到不同的节点上执行,可以有效减轻数据库的读压力,提高系统的性能和并发能力。

  • 导入依赖:

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.0</version>
    </dependency>
  • 配置数据源:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    spring:
    shardingsphere:
    datasource:
    master:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.241:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
    names: master,slave1,slave2
    slave1:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.242:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
    slave2:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.243:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
  • 配置读写分离策略:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    spring:
    shardingsphere:
    enabled: true
    props:
    # 打印sql
    sql:
    show: true
    sql-show: true
    rules:
    readwrite-splitting:
    data-sources:
    # 配置负载均衡器
    load-balancers:
    # 轮询算法
    roundRobin:
    type: ROUND_ROBIN
    # 代理数据源的名字
    master-slave:
    props:
    auto-aware-data-source-name: master
    # 负载均衡器名字,同上
    load-balancer-name: roundRobin
    # 读数据源
    read-data-source-names: slave1,slave2
    # 写数据源
    write-data-source-name: master
    # 读写分离类型,如Static、Dynamic(动态获取节点信息)
    type: Static
  • 使用orm框架直接进行crud即可(数据源已经被接管了,写会只放在主节点,读负载在从节点)

对于一些数据一致性要求高的场景,可以添加事务注解让其强制走主库

垂直分片

在 ShardingJDBC 中,垂直分片是指根据数据库表的列将数据划分到不同的数据库实例中。这种方式可以根据应用的需求,将相关性较低但数据量较大的列分配到不同的数据库中,以减轻单个数据库的负载压力。

  • 配置数据源:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    spring:
    shardingsphere:
    datasource:
    ds1:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.241:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
    names: ds1,ds2
    ds2:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.242:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
  • 配置垂直分片策略:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    spring:
    shardingsphere:
    rules:
    sharding:
    tables:
    # 垂直分表1
    t_userinfo:
    # 对应的数据库表
    actual-data-nodes: ds1.t_userinfo
    # 垂直分表1
    t_userpwd:
    # 对应的数据库表
    actual-data-nodes: ds2.t_userpwd
  • 使用orm框架直接进行crud即可(数据源已经被接管了)

水平分片

在 ShardingJDBC 中,水平分片的主要思想是根据某个字段的值将数据分散存储到不同的数据库或数据表中。ShardingJDBC 提供了多种分片算法:取模分片、哈希分片、基于分片容量的范围分片、分片边界的范围分片、自动时间段分片等多种分片算法

  • 配置多数据源与分片策略

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    spring:
    shardingsphere:
    datasource:
    ds0:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.241:3306/testdb
    password: root
    username: root
    ds1:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.242:3306/testdb
    password: root
    username: root
    ds2:
    driver‐class‐name: com.mysql.jdbc.Driver
    jdbc‐url: jdbc:mysql://192.168.31.243:3306/testdb
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    username: root
    names: ds0,ds1,ds2
  • 配置水平分片策略,利用行表达分片:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    spring:
    shardingsphere:
    #显示分库分表后执行的SQL语句
    props:
    sql‐show: true
    rules:
    sharding:
    # 默认主键生成策略采用snowflake
    default‐key‐generate‐strategy:
    xxx: snowflake
    key‐generators:
    snowflake:
    props:
    #机器唯一标识
    worker‐id: 666
    #SNOWFLAKE算法配置
    type: SNOWFLAKE
    # 定义数据源的分片规则,按employee表的id % 3 取模得到数据应放在哪个数据源
    sharding‐algorithms:
    database‐inline:
    props:
    algorithm‐expression: ds$‐>{id % 3}
    type: INLINE
    table‐inline:
    props:
    algorithm‐expression: employee$‐>{id % 3}
    type: INLINE
    tables:
    employee:
    # 该表对应的真实数据库表
    actual-data-nodes: ds$->{0..2}.employee->{0..2}
    # 分库策略
    database‐strategy:
    standard:
    # 将employee表与分片规则database‐inline绑定
    sharding‐algorithm‐name: database‐inline
    # 定义employee表哪个是分片字段,这里按主键字段id
    sharding‐column: id
    # 分表策略
    table‐strategy:
    standard:
    # 将employee表与分片规则database‐inline绑定
    sharding‐algorithm‐name: table‐inline
    # 定义employee表哪个是分片字段,这里按empNo
    sharding‐column: empNo
    # 定义哪一个列用于生成主键
    key‐generate‐strategy:
    column: id
    key-generator-name: snowflake
  • 使用orm框架直接进行crud即可(数据源已经被接管了)

配置关联表与广播表

在ShardingJDBC中配置关联表涉及到分库分表的数据库拆分策略。当存在多个关联的表时,需要确保它们能够在分布式环境下正确地进行数据关联和查询(不绑定关联表会发生笛卡尔积进行查询),这个时候就需要配置关联表。

  • 数据源配置不变,并保持多个关联表的分片策略一致(避免跨库关联)

  • 多添加关联表策略:将表1,表2(逻辑表名)进行绑定

    1
    spring.shardingsphere.rules.sharding.binding-tables[0]=表1,表2

    如果存在一个表需要跟几乎所有表都产生关联,例如字典表,那就需要申明为广播表:

    广播具有以下特性:

    • 插入、更新操作会实时在所有节点上执行,保持各个分片的数据一致性
    • 查询操作,只从一个节点获取
    • 可以跟任何一个表进行JOIN操作工
    1
    >spring.shardingsphere.rules.sharding.broadcast-tables[0]=表1,表2