ShardingSphere5.x 分库分表

一、shardingSphere介绍

1、官网:Apache ShardingSphere

2、开发文档: 概览 :: ShardingSphere

3、shardingsphere-jdbc

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

官网示例图:

4、shardingSphere-proxy

 定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。

官网示例图:

 5、两者的区别

 二、使用docker安装mysql服务器

1、docker未安装的请看

docker环境安装

注意如果此时防火墙是开启的,则先关闭防火墙,并重启docker,否则后续安装的MySQL无法启动(或者在服务器开放对应的端口号,可以提前开启3301,3302,3306,3307,3308,3310,3311,3321)

#关闭docker
systemctl stop docker
#关闭防火墙
systemctl stop firewalld
#启动docker
systemctl start docker

2、在docker中创建并启动MySQL主服务器

第一步:创建并启动mysql

docker run -d \
-p 3306:3306 \
-v /usr/local/docker/mysql/master/conf:/etc/mysql/conf.d \
-v /usr/local/docker/mysql/master/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name lkx-mysql-master \
mysql:8.0.29

第二步:创建MySQL主服务器配置文件

vim /usr/local/docker/mysql/master/conf/my.cnf

将以下配置复制进去并保存

[mysqld]
# 服务器唯一id,默认值1
server-id=1
# 设置日志格式,默认值ROW
binlog_format=STATEMENT
# 二进制日志名,默认binlog
# log-bin=binlog
# 设置需要复制的数据库,默认复制全部数据库
#binlog-do-db=mytestdb
# 设置不需要复制的数据库
#binlog-ignore-db=mysql
#binlog-ignore-db=infomation_schema

binlog格式说明:

  • binlog_format=STATEMENT:日志记录的是主机数据库的写指令,性能高,但是now()之类的函数以及获取系统参数的操作会出现主从数据不同步的问题。

  • binlog_format=ROW(默认):日志记录的是主机数据库的写后的数据,批量操作时性能较差,解决now()或者 user()或者 @@hostname 等操作在主从机器上不一致的问题。

  • binlog_format=MIXED:是以上两种level的混合使用,有函数用ROW,没函数用STATEMENT,但是无法识别系统变量

第三步: 重启MySQL容器

docker restart lkx-mysql-master

restart:重启

start:启动

stop:停止

第四步:使用命令行登录MySQL主服务器 ,并使root账号在数据库可视化工具可以连接

#进入容器:env LANG=C.UTF-8 避免容器中显示中文乱码
docker exec -it lkx-mysql-master env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码校验方式
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第五步:主机中创建slave用户

-- 创建slave用户
CREATE USER 'lkx_slave'@'%';
-- 设置密码
ALTER USER 'lkx_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'lkx_slave'@'%';
-- 刷新权限
FLUSH PRIVILEGES; 

第六步:查看主服务器的binlog文件名以及位置号

注意:此操作后不再操作此主mysql服务器,防止主服务器状态值变化

SHOW MASTER STATUS;

此时记录:binlog.0000003      1357两个值

3、在docker中创建并启动两个MySql从服务器

【1】重复执行创建MySql主服务器的,第一步到第四步,按顺序执行两遍。注意映射的端口号与容器名称别一样,这里自定义就行。

我这里举个例子:

docker run -d \
-p
3307:3306 \
-v /usr/local/docker/mysql/slave1/conf:/etc/mysql/conf.d \
-v /usr/local/docker/mysql/slave1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name
lkx-mysql-slave1 \
mysql:8.0.29


docker run -d \
-p
3308:3306 \
-v /usr/local/docker/mysql/slave2/conf:/etc/mysql/conf.d \
-v /usr/local/docker/mysql/slave2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name
lkx-mysql-slave2 \
mysql:8.0.29

【2】在从机上配置主从关系

注意:一定要在从机上操作,并且两台从机都要执行

CHANGE MASTER TO MASTER_HOST='47.97.68.78', 
MASTER_USER='lkx_slave',MASTER_PASSWORD='123456', MASTER_PORT=3306,
MASTER_LOG_FILE='binlog.000003',MASTER_LOG_POS=1357; 

【3】启动主从同步 

-- 在从服务器下查看状态(不需要分号)
SHOW SLAVE STATUS\G

我这边binlog文件名与位置不一样是因为我重启过服务,所以这里你们显示的就是上一步配置的binlog文件名与位置号

两个关键进程:下面两个参数都是Yes,则说明主从配置成功!

可能会出现一下情况,这时候表示从机的IO还没启动好,此时在等等然后再查看。

【4】测试主从同步的情况

在主机中执行以下SQL,在从机中查看数据库、表和数据是否已经被同步。或者直接在可视化工具下操作主MySql服务器,然后看从MySql服务器是否同步

CREATE DATABASE db_user;
USE db_user;
CREATE TABLE t_user (
 id BIGINT AUTO_INCREMENT,
 uname VARCHAR(30),
 PRIMARY KEY (id)
);
INSERT INTO t_user(uname) VALUES('zhang3');
INSERT INTO t_user(uname) VALUES(@@hostname);

三、ShardingSphere-JDBC读写分离

1、创建SpringBoot项目

2、引入maven依赖

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

    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
        <version>5.1.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.1</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

3、读写分离配置文件

server:
  port: 8888
spring:
  # 应用名称
  application:
    name: ShardingSphere-JDBC
  # 开发环境设置
  profiles:
    active: dev
  shardingsphere:
    datasource:
      # 配置真实数据源
      names: master,slave1,slave2
      master:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3306/db_user?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      slave1:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3307/db_user?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      slave2:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3308/db_user?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
    # 内存模式
    mode:
      type: Memory
    # 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2
    props:
      sql-show: true
    rules:
      readwrite-splitting:
        data-sources:
          myds:
            # 负载均衡算法名称 自定义
            load-balancer-name: alg_round
            props:
              # 读数据源名称,多个从数据源用逗号分隔
              read-data-source-names: slave1,slave2
              # 写数据源名称
              write-data-source-name: master
            # 读写分离类型,如: Static,Dynamic
            type: Static
        load-balancers:
          alg_random:
            type: RANDOM
          alg_round:
            type: ROUND_ROBIN
          alg_weight:
            props:
              slave1: 1
              slave2: 2
            type: WEIGHT

4、创建实体类

@TableName("t_user")
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String uname;
}

5、创建Mapper

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

6、测试

6.1:读写分离测试

@Autowired
    private UserMapper userMapper;

    /**
     * 不添加@Transactional:insert对主库操作,select对从库操作
     */
    @Test
    public void insertTest() {
        User user = new User();
        user.setUname("lkx1");
        user.setCreateTime(new Date());
        userMapper.insert(user);
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }

 效果:

Actual SQL: master ::: INSERT  可以看出insert语句实在master这个配置的数据源执行的

Actual SQL: slave1 ::: SELECT  可以看出查询实在slave1从库其中一个执行的

6.2:事务测试

/**
     * 添加@Transactional:则insert和select均对主库操作
     */
    @Test
    @Transactional
    public void insertOfTransactionalTest() {
        User user = new User();
        user.setUname("lkx_transactional");
        user.setCreateTime(new Date());
        userMapper.insert(user);
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }

效果:

可以看出insert与select都是在master数据源库进行处理的,然后因为添加了事务,所以在测试环境就会数据回滚

6.3:负载均衡读测试

/**
     * 读数据测试
     */
    @Test
    public void testSelectAll(){
        List<User> users1 = userMapper.selectList(null);
        List<User> users2 = userMapper.selectList(null);//执行第二次测试负载均衡
    }

效果:

可以看出两个从库每个执行一边select语句,我这使用的是轮询的算法。这里可以修改规则,有轮询、随机、权重三个规则。可以修改对应想要的查询算法

四、ShardingSphere-JDBC垂直分片

准备:使用docker创建两个容器

  • 服务器:容器名server-user,端口3301

  • 服务器:容器名server-order,端口3302

4.1、创建server-user容器

第一步:创建容器

docker run -d \
-p 3301:3306 \
-v /usr/local/docker/server/user/conf:/etc/mysql/conf.d \
-v /usr/local/docker/server/user/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-user \
mysql:8.0.29

第二步:登录MySQL服务器

#进入容器:
docker exec -it server-user env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第三步:创建数据库 ​​​​​​​

CREATE DATABASE db_user;
USE db_user;
CREATE TABLE t_user (
 id BIGINT AUTO_INCREMENT,
 uname VARCHAR(30),
 PRIMARY KEY (id)
);

4.2、创建server-order容器

第一步:创建容器

docker run -d \
-p 3302:3306 \
-v /usr/local/docker/server/order/conf:/etc/mysql/conf.d \
-v /usr/local/docker/server/order/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order \
mysql:8.0.29

第二步:登录MySQL服务器

#进入容器:
docker exec -it server-order env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第三步:创建数据库 ​​​​​​​

CREATE DATABASE db_user;
USE db_user;
CREATE TABLE t_user (
 id BIGINT AUTO_INCREMENT,
 uname VARCHAR(30),
 PRIMARY KEY (id)
);

4.3、创建SpringBoot项目实现

4.3.1、引入maven

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

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>5.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

4.3.2、配置配置文件

server:
  port: 8887
spring:
  # 应用名称
  application:
    name: ShardingSphere-JDBC-Vertical-branch-library
  # 开发环境设置
  profiles:
    active: dev
  shardingsphere:
    datasource:
      # 配置真实数据源
      names: server-user,server-order
      server-user:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3301/db_user?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      server-order:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3302/db_order?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
    # 内存模式
    mode:
      type: Memory
    # 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2
    props:
      sql-show: true
    rules:
      sharding:
        tables:
          t_user:
#            actual-data-nodes: server-user.t_user_${0..1}
            actual-data-nodes: server-user.t_user
          t_order:
            actual-data-nodes: server-order.t_order

4.3.3、创建实体与Mapper文件

@TableName("t_order")
@Data
public class Order {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String orderNo;
    private Long userId;
    private BigDecimal amount;
}
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

4.3.4、测试

【1】测试插入
@Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserMapper userMapper;


    @Test
    void testInsertUserAndOrder(){
        User user = new User();
        user.setUname("lkx777");
        user.setCreateTime(new Date());
        userMapper.insert(user);

        Order order = new Order();
        order.setUserId(user.getId());
        order.setOrderNo("O123457");
        order.setAmount(new BigDecimal("100"));
        orderMapper.insert(order);
    }

效果:

由此可见,插入的时候是插入到不同的库中。

【2】测试查询
/**
     * 垂直分片:查询数据测试
     */
    @Test
    public void testSelectFromOrderAndUser(){
        User user = userMapper.selectById(1L);
        Order order = orderMapper.selectById(1L);
    }

效果:

五、ShardingSphere-JDBC水平分片(*重点*

准备:使用docker创建两个容器

5.1、创建server-order0容器

第一步:创建容器

  • 服务器:容器名server-order0,端口3310

  • 服务器:容器名server-order1,端口3311

docker run -d \
-p 3310:3306 \
-v /usr/local/docker/server/order0/conf:/etc/mysql/conf.d \
-v /usr/local/docker/server/order0/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order0 \
mysql:8.0.29

​​​​​​​第二步:登录MySQL服务器

#进入容器:
docker exec -it server-order0 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第三步:创建数据库

注意水平分片的id需要在业务层实现,不能依赖数据库的主键自增(否则不同库会出现相同的主键)

CREATE DATABASE db_order;
USE db_order;
CREATE TABLE t_order0 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);
CREATE TABLE t_order1 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);

5.2、创建server-order1容器

第一步:创建容器

docker run -d \
-p 3311:3306 \
-v /usr/local/docker/server/order1/conf:/etc/mysql/conf.d \
-v /usr/local/docker/server/order1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name server-order1 \
mysql:8.0.29

​​​​​​​第二步:登录MySQL服务器

​​​​​​​#进入容器:
docker exec -it server-order1 env LANG=C.UTF-8 /bin/bash
#进入容器内的mysql命令行
mysql -uroot -p
#修改默认密码插件
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第三步:创建数据库

注意水平分片的id需要在业务层实现,不能依赖数据库的主键自增(否则不同库会出现相同的主键)

CREATE DATABASE db_order;
USE db_order;
CREATE TABLE t_order0 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);
CREATE TABLE t_order1 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);

5.3、创建SpringBoot项目实现

5.3.1、引入maven

<dependencies>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>5.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

5.3.2、配置配置文件

总配置文件:

server:
  port: 8886
spring:
  # 应用名称
  application:
    name: demoShardingSphere-JDBC-horizontal-fragmentation
  # 开发环境设置
  profiles:
    active: dev
  shardingsphere:
    datasource:
      # 配置真实数据源
      names: server-user,server-order0,server-order1
      server-user:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3301/db_user?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      server-order0:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3310/db_order?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      server-order1:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://47.97.68.78:3311/db_order?characterEncoding=utf-8
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
    # 内存模式
    mode:
      type: Memory
    # 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2
    props:
      sql-show: true
    # spring.shardingsphere.rules.sharding.tables.<table-name>.actual-data-nodes=值
    # 值由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。 server-order$->{0..1}.t_order$->{0..1}
    # <table-name>:逻辑表名
    rules:
      sharding:
        tables:
          t_user:
            #            actual-data-nodes: server-user.t_user_${0..1}
            actual-data-nodes: server-user.t_user
          t_order:
#            actual-data-nodes: server-order0.t_order0,server-order0.t_order1,server-order1.t_order0,server-order1.t_order1
            actual-data-nodes: server-order$->{[0,1]}.t_order$->{[0,1]}
#            actual-data-nodes: server-order$->{[0,1]}.t_order0
            # ---------------分库策略
            database-strategy:
              standard:
                # 分片列名称
                sharding-column: user_id
                # 分片算法名称
                sharding-algorithm-name: alg_inline_userid
            # ---------------分表策略
            table-strategy:
              standard:
                # 分片列名称
                sharding-column: order_no
                # 分片算法名称
                sharding-algorithm-name: alg_hash_mod
            #------------------------分布式序列策略配置
            key-generate-strategy:
              # 分布式序列列名称
              column: id
              # 分布式序列算法名称
              key-generator-name: alg_snowflake
          t_order_item:
            actual-data-nodes: server-order$->{[0,1]}.t_order_item$->{[0,1]}
            # ---------------分库策略
            database-strategy:
              standard:
                # 分片列名称
                sharding-column: user_id
                # 分片算法名称
                sharding-algorithm-name: alg_inline_userid
            # ---------------分表策略
            table-strategy:
              standard:
                # 分片列名称
                sharding-column: order_no
                # 分片算法名称
                sharding-algorithm-name: alg_hash_mod
            #------------------------分布式序列策略配置
            key-generate-strategy:
              # 分布式序列列名称
              column: id
              # 分布式序列算法名称
              key-generator-name: alg_snowflake
          t_dict:
            actual-data-nodes: server-user.t_dict,server-order$->{[0,1]}.t_dict
        sharding-algorithms:
          # 行表达式分片算法   alg_inline_userid 是取的对应的算法名称,这里可自定义
          alg_inline_userid:
            # 分片算法类型
            type: INLINE
            # 分片算法属性配置
            props:
              algorithm-expression: server-order$->{user_id % 2}
          # 取模分片算法   alg_mod 是取的对应的算法名称,这里可自定义
          alg_mod:
            # 分片算法类型
            type: MOD
            # 分片算法属性配置
            props:
              sharding-count: 2
          alg_hash_mod:
            type: HASH_MOD
            props:
              sharding-count: 2
      # 分布式序列算法配置
        key-generators:
          alg_snowflake:
            # 分布式序列算法类型
            type: SNOWFLAKE
        # 绑定表规则列表
        #使用绑定表进行多表关联查询时,必须使用分片键(user_id,order_no)进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。
        binding-tables[0]: t_order,t_order_item
        # 广播表
        broadcast-tables[0]: t_dict

分库配置:

spring:
  shardingsphere:
    rules:
      sharding:
        #------------------------分片算法配置
        sharding-algorithms:
          alg_inline_userid:
            # 分片算法属性配置
            props:
              algorithm-expression: server-order$->{user_id % 2}
            # 分片算法类型
            type: INLINE
          alg_mod:
            # 分片算法属性配置
            props:
              sharding-count: 2
            # 分片算法类型
            type: MOD
        tables:
          t_order:
            #------------------------分库策略
            database-strategy:
              standard:
                # 分片算法名称
                sharding-algorithm-name: alg_inline_userid
                # 分片列名称
                sharding-column: user_id

分表配置:

spring:
  shardingsphere:
    rules:
      sharding:
        #------------------------分片算法配置
        # 哈希取模分片算法
        sharding-algorithms:
          alg_hash_mod:
            # 分片算法属性配置
            props:
              sharding-count: 2
            # 分片算法类型
            type: HASH_MOD
        tables:
          t_order:
            #------------------------分库策略
            table-strategy:
              standard:
                # 分片算法名称
                sharding-algorithm-name: alg_hash_mod
                # 分片列名称
                sharding-column: order_no

5.3.3、测试

【1】插入测试
 /**
     * 水平分片:分表插入数据测试
     */
    @Test
    public void testInsertOrderTableStrategy(){

        for (long i = 100; i < 104; i++) {

            Order order = new Order();
            order.setOrderNo("O" + i);
            order.setUserId(1L);
            order.setAmount(new BigDecimal(100));
            orderMapper.insert(order);
        }

        for (long i = 105; i < 109; i++) {

            Order order = new Order();
            order.setOrderNo("O" + i);
            order.setUserId(2L);
            order.setAmount(new BigDecimal(100));
            orderMapper.insert(order);
        }
    }

效果:

【2】查询测试 
/**
     * 水平分片:查询所有记录
     * 查询了两个数据源,每个数据源中使用UNION ALL连接两个表
     */
@Test
public void testShardingSelectAll(){

    List<Order> orders = orderMapper.selectList(null);
    orders.forEach(System.out::println);
}

/**
     * 水平分片:根据user_id查询记录
     * 查询了一个数据源,每个数据源中使用UNION ALL连接两个表
     */
@Test
public void testShardingSelectByUserId(){

    QueryWrapper<Order> orderQueryWrapper = new QueryWrapper<>();
    orderQueryWrapper.eq("user_id", 1L);
    List<Order> orders = orderMapper.selectList(orderQueryWrapper);
    orders.forEach(System.out::println);
}

效果:有一些我的老数据可忽略结果,直接看sql

5.4、多表关联

5.4.1、创建关联表

server-order0、server-order1服务器中分别创建两张订单详情表t_order_item0、t_order_item1

我们希望同一个用户的订单表和订单详情表中的数据都在同一个数据源中,避免跨库关联,因此这两张表我们使用相同的分片策略。

那么在t_order_item中我们也需要创建order_nouser_id这两个分片键

CREATE TABLE t_order_item0(
    id BIGINT,
    order_no VARCHAR(30),
    user_id BIGINT,
    price DECIMAL(10,2),
    `count` INT,
    PRIMARY KEY(id)
);

CREATE TABLE t_order_item1(
    id BIGINT,
    order_no VARCHAR(30),
    user_id BIGINT,
    price DECIMAL(10,2),
    `count` INT,
    PRIMARY KEY(id)
);

5.4.2、创建实体类与Mapper

@TableName("t_order_item")
@Data
public class OrderItem {
    //当配置了shardingsphere-jdbc的分布式序列时,自动使用shardingsphere-jdbc的分布式序列
    @TableId(type = IdType.AUTO)
    private Long id;
    private String orderNo;
    private Long userId;
    private BigDecimal price;
    private Integer count;
}
@Mapper
public interface OrderItemMapper extends BaseMapper<OrderItem> {

}

5.4.3、关联表相关配置

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order_item:
            #------------------------标准分片表配置(数据节点配置)
            actual-data-nodes: server-order$->{0..1}.t_order_item$->{0..1}
            #------------------------分库策略
            database-strategy:
              standard:
                # 分片算法名称
                sharding-algorithm-name: alg_mod
                # 分片列名称
                sharding-column: user_id
            #------------------------分布式序列策略配置
            key-generate-strategy:
              # 分布式序列列名称
              column: id
              # 分布式序列算法名称
              key-generator-name: alg_snowflake
            #------------------------分表策略
            table-strategy:
              standard:
                # 分片算法名称
                sharding-algorithm-name: alg_hash_mod
                # 分片列名称
                sharding-column: order_no

5.4.4、测试

【1】插入测试
/**
     * 测试关联表插入
     */
    @Test
    public void testInsertOrderAndOrderItem(){

        for (long i = 1; i < 3; i++) {

            Order order = new Order();
            String orderNo = "O" + i;
            order.setOrderNo(orderNo);
            order.setUserId(1L);
            orderMapper.insert(order);

            for (long j = 1; j < 3; j++) {
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderNo(orderNo);
                orderItem.setUserId(1L);
                orderItem.setPrice(new BigDecimal(10));
                orderItem.setCount(2);
                orderItemMapper.insert(orderItem);
            }
        }

        for (long i = 5; i < 7; i++) {

            Order order = new Order();
            String orderNo = "O" + i;
            order.setOrderNo(orderNo);
            order.setUserId(2L);
            orderMapper.insert(order);

            for (long j = 1; j < 3; j++) {
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderNo(orderNo);
                orderItem.setUserId(2L);
                orderItem.setPrice(new BigDecimal(1));
                orderItem.setCount(3);
                orderItemMapper.insert(orderItem);
            }
        }

    }
【2】查询测试
@Data
public class OrderVo {
    private String orderNo;
    private BigDecimal amount;
}
 /**
     * 测试关联表查询
     */
    @Test
    public void testGetOrderAmount(){

        List<OrderVo> orderAmountList = orderMapper.getOrderAmount();
        orderAmountList.forEach(System.out::println);
    }
<select id="getOrderAmount" resultType="com.lkx.horizontalfragmentation.entity.OrderVo">
        SELECT o.order_no, SUM(i.price * i.count) AS amount
        FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no
        GROUP BY o.order_no
    </select>

5.5、配置绑定表

配置:

spring:
  shardingsphere:
    rules:
      sharding:
        binding-tables[0]: t_order,t_order_item

配置完绑定表后再次进行关联查询的测试:

  • 如果不配置绑定表:测试的结果为8个SQL。多表关联查询会出现笛卡尔积关联。

  • 如果配置绑定表:测试的结果为4个SQL。 多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

绑定表:指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。

六、ShardingSphere-Proxy

​​​​​​​

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ShardingSphere 5.x 范围分片是一种数据分片策略,在分布式数据库中用于管理和存储大量数据。范围分片是指根据数据的范围将数据划分到不同的物理节点上。下面我将详细介绍 ShardingSphere 5.x 范围分段的工作原理。 首先,范围分片会将数据按照指定的范围进行划分,比如按照时间范围、数字范围等。例如,我们可以按照订单时间将订单数据划分到不同的分片中,比如将近一个月内的订单数据划分到一个分片,下一个月的订单数据划分到另一个分片。 其次,ShardingSphere 5.x 范围分段通过指定的分片键来确定数据所属的分片,该分片键可以是数据表中的某个字段,比如订单表中的时间字段。通过对分片键的范围划分,可以将数据精确地分布到不同的分片中,实现数据的水平拆分和存储。 另外,ShardingSphere 5.x 范围分段还具有动态扩容和缩容的功能。当数据量增长或减少时,可以根据需求动态地添加或删除分片,实现分片的动态调整。 最后,ShardingSphere 5.x 范围分段还提供了分片路由和分片合并的功能。分片路由用于将查询请求路由到正确的分片上进行查询,而分片合并用于将来自不同分片的查询结果合并成一个统一的结果集。 总的来说,ShardingSphere 5.x 范围分段是一种高效的数据分片策略,能够帮助分布式系统管理和存储大量的数据,提高系统的性能和扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lin_XXiang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值