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

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404475.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统化学习】深入理解匿名管道(pipe)和命名管道(fifo)

目录 进程间通信 进程间通信目的 进程间通信的方式 管道 System V IPC&#xff08;本地通信&#xff09; POSIX IPC&#xff08;网络通信&#xff09; 管道 什么是管道 匿名管道 匿名管道的创建 匿名管道的使用 匿名管道的四种情况 匿名管道的五种特性 命名管道 …

VSCODE上使用python_Django_创建最小项目

接上篇 https://blog.csdn.net/weixin_44741835/article/details/136135996?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22136135996%22%2C%22source%22%3A%22weixin_44741835%22%7D VSCODE官网&#xff1a; Editing Python …

无人机快递(物流)技术方案,无人机快递(物流)基础知识

无人机快递技术是一种利用无人机进行快递配送的先进技术。通过利用无人机&#xff0c;快递企业能够在偏远地区或难以通行的地区提供配送服务&#xff0c;同时提高配送效率并降低人力成本。 无人机基本情况 无人驾驶飞机简称“无人机”&#xff0c;是利用无线电遥控设备和自备的…

SQLite 的使用

SQLite 是一个轻量级、自包含和无服务器的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于嵌入式系统、移动应用程序和小中型网站。它易于创建、需要的配置较少&#xff0c;并且提供了用于管理和操作数据的强大功能集。本文&#xff0c;我们将带领你…

linux---防火墙拓展

目录 一、iptables 1.基本语法 2.四表五链——重点记忆 2.1四表 2.2五链 2.3总结 3.iptables选项示例 3.1 -Z 清空流量计数 3.2 -P 修改默认规则 3.3 -D 删除规则 3.4 -R 指定编号替换规则 4.白名单 5.通用匹配 6.示例 6.1添加回环网卡 6.2可以访问端口 6.3 主…

Encoder-decoder 与Decoder-only 模型之间的使用区别

承接上文&#xff1a;Transformer Encoder-Decoer 结构回顾 笔者以huggingface T5 transformer 对encoder-decoder 模型进行了简单的回顾。 由于笔者最近使用decoder-only模型时发现&#xff0c;其使用细节和encoder-decoder有着非常大的区别&#xff1b;而huggingface的接口为…

设计模式——抽象工厂模式

定义: 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;提供一个创建一系列或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 概述:一个工厂可以提供创建多种相关产品的接口&#xff0c;而无需像工厂方法一样&#xff0c;为每一个产品都提供一个具体…

【开源】JAVA+Vue.js实现医院门诊预约挂号系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 功能性需求2.1.1 数据中心模块2.1.2 科室医生档案模块2.1.3 预约挂号模块2.1.4 医院时政模块 2.2 可行性分析2.2.1 可靠性2.2.2 易用性2.2.3 维护性 三、数据库设计3.1 用户表3.2 科室档案表3.3 医生档案表3.4 医生放号…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的遥感目标检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;本文介绍了一种基于深度学习的遥感目标检测系统系统的代码&#xff0c;采用最先进的YOLOv8算法并对比YOLOv7、YOLOv6、YOLOv5等算法的结果&#xff0c;能够准确识别图像、视频、实时视频流以及批量文件中的遥感目标。文章详细解释了YOLOv8算法的原理&#xff0…

力扣226 翻转二叉树 Java版本

文章目录 题目描述解题思路代码 题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root…

智慧物业信息管理系统平台及APP建设项目

随着城市化步伐的不断加快&#xff0c;物业管理成为城市建设中不可或缺的一部分。为了更好地满足各方对物业管理的全面需求&#xff0c;智慧物业信息管理系统平台及APP项目&#xff0c;融合了八大子系统&#xff0c;旨在为其提供更全面、高效的物业管理解决方案。 1. 物业信用…

盘点自动化汽车生产线设备 数据采集分析联合各设备

1.机器人自动装配线 机器人自动装配线已成为汽车制造业中的常见场景。这些机器人在汽车组装的各个环节发挥关键作用&#xff0c;从焊接和铆接到零部件组装。它们不仅提高了装配速度&#xff0c;还确保了产品的一致性&#xff0c;降低了废品率。 2.3D打印技术 3D打印技术正在汽车…

Draw.io绘制UML图教程

一、draw.io介绍 1、draw.io简介 draw.io 是一款强大的免费在线图表绘制工具&#xff0c;支持创建流程图、组织结构图、时序图等多种图表类型。它提供丰富的形状库、强大的文本编辑和样式设置功能&#xff0c;使用户能够轻松创建专业级图表。draw.io 具有用户友好的界面&…

UTONMOS开启数智龙年,打造元宇宙游戏圈新名片

新年已过&#xff0c;全国各个城市早已客流涌动、热闹非凡。这种繁华景象不仅存在于现实世界&#xff0c;也被复刻到元宇宙的虚拟空间中。 据介绍&#xff0c;UTONMOS“源起山海-神念无界”元宇宙游戏是以原创IP玄幻神话故事“元宇宙史纪”为蓝本打造的元宇宙游戏空间&#xf…

图文说明Linux云服务器如何更改实例镜像

一、应用场景举例 在学习Linux的vim时&#xff0c;我们难免要对vim进行一些配置&#xff0c;这里我们提供一个vim插件的安装包&#xff1a; curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o./install.sh && bash ./install.sh 但是此安装包…

可变形注意力(Deformable Attention)及其拓展

文章目录 一、补充知识&#xff08;一&#xff09;可变形卷积&#xff08;Deformable Convolution&#xff09;&#xff08;二&#xff09;多头注意力机制 二、可变形注意力模块三、可变形自注意力模块&#xff08;一&#xff09;偏移模块&#xff1a;&#xff08;二&#xff0…

“比特币暴涨讯号显现”!减半牛市来临前还有一次震撼回撤?“52000美元保卫战”已经打响!

虽然比特币在20日一度冲高至近5.3万美元大关&#xff0c;创下自2021年11月来新高&#xff0c;但随后开始回落&#xff0c;在51000美元至52000美元之间反复窄幅波动&#xff0c;甚至在21日晚一度跌至50625美元。比特币的未来走势&#xff0c;已牵动不少投资者的心。 自1月底比特…

华为OD机试真题-来自异国的客人-2023年OD统一考试(C卷)--Python3--开源

题目&#xff1a; 考察内容&#xff1a; 10进制转为任何进制 代码&#xff1a; """ 题目分析&#xff1a;输入&#xff1a; k --物品价值&#xff1b;n 幸运数字&#xff1b;m 进制 输出&#xff1a; 幸运数字的个数 异常&#xff1b;0 eg; 10 2 4思路&…

STM32—触摸键

目录 1 、 电路构成及原理图 2 、编写实现代码 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 触摸键简单的了解就是一次电容的充放电过程。从原理图可以看出&#xff0c;触摸键 …

代码随想录算法训练营第21天—回溯算法01 | ● 理论基础 ● *77. 组合

理论基础 回溯是一种纯暴力搜索的方法&#xff0c;它和递归相辅相成&#xff0c;通常是执行完递归之后紧接着执行回溯相较于以往使用的for循环暴力搜索&#xff0c;回溯能解决更为复杂的问题&#xff0c;如以下的应用场景应用场景 组合问题 如一个集合{1,2,3,4}&#xff0c;找…