sharding-jdbc-springboot简单样例

ShardingSphere官方文档

ShardingSphere

样例源代码

sharding-jdbc-springboot

1,sharding-jdbc 基本概念

逻辑表 :水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0 到 t_order_9,他们的逻辑表名为 t_order。

真实表:数据库中真实存在的物理表。即上个示例中的 t_order_0 到 t_order_9。

数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0。

绑定表:分片规则一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系。

广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。例如:字典表。

分片键:将数据库(表)水平拆分的关键字段

分片算法:

通过分片算法将数据分片。

StandardShardingAlgorithm:标准分片算法,用于处理使用单一键作为分片键的 =、IN、BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合 StandardShardingStrategy 使用。

ComplexKeysShardingAlgorithm :复合分片算法,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合 ComplexShardingStrategy 使用。

HintShardingAlgorithm :Hint分片算法,用于处理使用 Hint 行分片的场景。需要配合 HintShardingStrategy 使用。

分片策略:

包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供 5 种分片策略。

StandardShardingStrategy:”标准分片策略。提供对 SQ L语句中的 =, >, <, >=, <=, IN 和 BETWEEN AND 的分片操作支持。 StandardShardingStrategy 只支持单分片键,提供 PreciseShardingAlgorithm 和 RangeShardingAlgorithm 两个分片算法。 PreciseShardingAlgorithm 是必选的,用于处理 = 和 IN 的分片。 RangeShardingAlgorithm 是可选的,用于处理 BETWEEN AND, >, <, >=, <=分片,如果不配置 RangeShardingAlgorithm,SQL 中的 BETWEEN AND 将按照全库路由处理。

ComplexShardingStrategy:复合分片策略。提供对 SQL 语句中的 =, >, <, >=, <=, IN 和 BETWEEN AND 的分片操作支持。 ComplexShardingStrategy 支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。

HintShardingStrategy:Hint分片策略,通过 Hint 指定分片值而非从 SQL 中提取分片值的方式进行分片的策略。

NoneShardingStrategy:不分片策略

行表达式

行表达式的使用非常直观,只需要在配置中使用 ${ expression } 或 $->{ expression } 标识行表达式即可。 目前支持数据节点和分片算法这两个部分的配置。行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。例如:

${begin…end} 表示范围区间

${[unit1, unit2, unit_x]} 表示枚举值

例如,以下行表达式:

$->{['online', 'offline']}_table$->{1..3}

最终会解析为:

online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3

2,实例

1,引入jar包

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!--aspect-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>
        <!--validation-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
    </dependencies>

2,配置

application.yml 文件

server:
  port: 8081
spring:
  shardingsphere:
    props:
      sql:
        # 打印sql
        show: true
    orchestration:
      registry:
        #操作超时的毫秒数,默认500毫秒
        operation-timeout-milliseconds: 600000
    datasource:
      names: ds0,ds0slave,ds1,ds1slave
      ds0:
        driverClassName: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        jdbcUrl: jdbc:mysql://192.168.16.128:3306/ds0?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
        # hikari 的线程池配置
        maximumPoolSize: 20
        minimumIdle: 10
      ds0slave:
        driverClassName: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        jdbcUrl: jdbc:mysql://192.168.16.129:3306/ds0?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
        # hikari 的线程池配置
        maximumPoolSize: 20
        minimumIdle: 10
      ds1:
        driverClassName: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        jdbcUrl: jdbc:mysql://192.168.16.128:3306/ds1?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
        # hikari 的线程池配置
        maximumPoolSize: 20
        minimumIdle: 10
      ds1slave:
        driverClassName: com.mysql.cj.jdbc.Driver
        type: com.zaxxer.hikari.HikariDataSource
        jdbcUrl: jdbc:mysql://192.168.16.129:3306/ds1?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=UTC
        username: root
        password: 123456
        # hikari 的线程池配置
        maximumPoolSize: 20
        minimumIdle: 10
    sharding:
      #未分片表的默认数据库
      default-data-source-name: ds0
      #读写分离
      master-slave-rules:
        ds0:
          master-data-source-name: ds0
          slave-data-source-names: ds0slave
        ds1:
          master-data-source-name: ds1
          slave-data-source-names: ds1slave
      tables:
        #分表案例
        users:
          actual-data-nodes: ds0.users_$->{0..1}
          key-generator:
            column: id
            type: SNOWFLAKE
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: users_$->{id % 2}
        #分表分库案例
        user_pack_records:
          actual-data-nodes: ds0.user_pack_records_$->{2018..2019},ds1.user_pack_records_$->{2020..2021}
          key-generator:
            column: id
            type: SNOWFLAKE
          database-strategy:
            standard:
              sharding-column: start_time
              precise-algorithm-class-name: com.sharding.jdbc.algorithm.db.UserPackRecordsAlgorithm
              range-algorithm-class-name: com.sharding.jdbc.algorithm.db.UserPackRecordsAlgorithm
          table-strategy:
            standard:
              sharding-column: start_time
              precise-algorithm-class-name: com.sharding.jdbc.algorithm.table.UserPackRecordsAlgorithm
              range-algorithm-class-name: com.sharding.jdbc.algorithm.table.UserPackRecordsAlgorithm
mybatis:
  configuration:
    #驼峰转化
    map-underscore-to-camel-case: true
  # Java 与 Mysql 的类型转化基础包
  type-handlers-package: com.sharding.jdbc.convert

3,自定义数据库分片算法


import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * user_pack_records 分库:阅读时间 start_time 在2018-2019 在 db0,2020-2021 在db1
 */
public class UserPackRecordsAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {

    /**
     * 通过年份获取真实数据库
     *
     * @param year 年份
     * @return 真实数据库
     */
    private String getDbByYear(Integer year) {
        if (year == 2018 || year == 2019) {
            return "ds0";
        } else if (year == 2020 || year == 2021) {
            return "ds1";
        }
        throw new IllegalArgumentException();
    }

    /**
     * PreciseShardingAlgorithm 是必选的,用于处理=和IN的分片。
     *
     * @param availableDbNames 可用的数据库集合
     * @param shardingValue    分片键
     * @return 真实数据库
     */
    @Override
    public String doSharding(Collection<String> availableDbNames, PreciseShardingValue<LocalDateTime> shardingValue) {
        int year = shardingValue.getValue().getYear();
        return getDbByYear(year);
    }

    /**
     * RangeShardingAlgorithm 可选,用于处理BETWEEN AND, >, <, >=, <=分片
     *
     * @param availableDbNames   可用的数据库集合
     * @param rangeShardingValue 分片键
     * @return 真实数据库
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableDbNames, RangeShardingValue<LocalDateTime> rangeShardingValue) {
        List<String> dbs = new ArrayList<>();
        int lowerYear = rangeShardingValue.getValueRange().lowerEndpoint().toLocalDate().getYear();
        LocalDate startDate = LocalDate.of(lowerYear, 1, 1);
        LocalDate endDate = rangeShardingValue.getValueRange().upperEndpoint().toLocalDate();
        for (LocalDate curDate = startDate; curDate.isBefore(endDate) || curDate.isEqual(endDate); curDate = curDate.plusYears(1)) {
            dbs.add(getDbByYear(curDate.getYear()));
        }
        return dbs;
    }
}

自定义分表算法

package com.sharding.jdbc.algorithm.table;

import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class UserPackRecordsAlgorithm implements PreciseShardingAlgorithm<LocalDateTime>, RangeShardingAlgorithm<LocalDateTime> {
    /**
     * 通过年份获取真实表
     *
     * @param year 年份
     * @return 真实表
     */
    private String getTableByYear(Collection<String> availableTargetNames, String year) {
        for (String targetName : availableTargetNames) {
            if (targetName.endsWith(year)) {
                return targetName;
            }
        }
        return null;
    }

    /**
     * PreciseShardingAlgorithm 是必选的,用于处理=和IN的分片。
     *
     * @param availableTargetNames 可用的表集合
     * @param shardingValue        分片键
     * @return 真实表
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<LocalDateTime> shardingValue) {
        LocalDateTime startTime = shardingValue.getValue();
        return getTableByYear(availableTargetNames, String.valueOf(startTime.getYear()));
    }

    /**
     * RangeShardingAlgorithm 可选,用于处理BETWEEN AND, >, <, >=, <=分片
     *
     * @param availableTargetNames 可用的表集合
     * @param rangeShardingValue   分片键
     * @return 真实表
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<LocalDateTime> rangeShardingValue) {
        List<String> tables = new ArrayList<>();
        int lowerYear = rangeShardingValue.getValueRange().lowerEndpoint().toLocalDate().getYear();
        LocalDate startDate = LocalDate.of(lowerYear, 1, 1);
        LocalDate endDate = rangeShardingValue.getValueRange().upperEndpoint().toLocalDate();
        for (LocalDate curDate = startDate; curDate.isBefore(endDate) || curDate.isEqual(endDate); curDate = curDate.plusYears(1)) {
            String table = getTableByYear(availableTargetNames, String.valueOf(curDate.getYear()));
            if (StringUtils.isNotBlank(table)) {
                tables.add(table);
            }
        }
        return tables;
    }
}

4,详细代码请进入githut看源代码
sharding-jdbc-springboot

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值