当前位置: 首页 > news >正文

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: devshardingsphere:datasource:# 配置真实数据源names: master,slave1,slave2master:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3306/db_user?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: rootslave1:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3307/db_user?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: rootslave2:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3308/db_user?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: root# 内存模式mode:type: Memory# 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2props:sql-show: truerules:readwrite-splitting:data-sources:myds:# 负载均衡算法名称 自定义load-balancer-name: alg_roundprops:# 读数据源名称,多个从数据源用逗号分隔read-data-source-names: slave1,slave2# 写数据源名称write-data-source-name: master# 读写分离类型,如: Static,Dynamictype: Staticload-balancers:alg_random:type: RANDOMalg_round:type: ROUND_ROBINalg_weight:props:slave1: 1slave2: 2type: 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:读写分离测试

@Autowiredprivate UserMapper userMapper;/*** 不添加@Transactional:insert对主库操作,select对从库操作*/@Testpublic 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@Transactionalpublic 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:负载均衡读测试

/*** 读数据测试*/@Testpublic 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: devshardingsphere:datasource:# 配置真实数据源names: server-user,server-orderserver-user:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3301/db_user?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: rootserver-order:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3302/db_order?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: root# 内存模式mode:type: Memory# 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2props:sql-show: truerules:sharding:tables:t_user:
#            actual-data-nodes: server-user.t_user_${0..1}actual-data-nodes: server-user.t_usert_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】测试插入
@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate UserMapper userMapper;@Testvoid 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】测试查询
/*** 垂直分片:查询数据测试*/@Testpublic 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: devshardingsphere:datasource:# 配置真实数据源names: server-user,server-order0,server-order1server-user:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3301/db_user?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: rootserver-order0:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3310/db_order?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: rootserver-order1:driver-class-name: com.mysql.jdbc.Driverjdbc-url: jdbc:mysql://47.97.68.78:3311/db_order?characterEncoding=utf-8password: 123456type: com.zaxxer.hikari.HikariDataSourceusername: root# 内存模式mode:type: Memory# 打印SQl   在控制台查看日志输出,可以知道此时是在哪个数据源进行操作。如:Actual SQL: slave2props: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_usert_order:
#            actual-data-nodes: server-order0.t_order0,server-order0.t_order1,server-order1.t_order0,server-order1.t_order1actual-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_snowflaket_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_snowflaket_dict:actual-data-nodes: server-user.t_dict,server-order$->{[0,1]}.t_dictsharding-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: 2alg_hash_mod:type: HASH_MODprops: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: INLINEalg_mod:# 分片算法属性配置props:sharding-count: 2# 分片算法类型type: MODtables: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_MODtables:t_order:#------------------------分库策略table-strategy:standard:# 分片算法名称sharding-algorithm-name: alg_hash_mod# 分片列名称sharding-column: order_no

5.3.3、测试

【1】插入测试
 /*** 水平分片:分表插入数据测试*/@Testpublic 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】插入测试
/*** 测试关联表插入*/@Testpublic 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;
}
 /*** 测试关联表查询*/@Testpublic 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 amountFROM t_order o JOIN t_order_item i ON o.order_no = i.order_noGROUP 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

​​​​​​​

相关文章:

ShardingSphere5.x 分库分表

一、shardingSphere介绍 1、官网&#xff1a;Apache ShardingSphere 2、开发文档&#xff1a; 概览 :: ShardingSphere 3、shardingsphere-jdbc ShardingSphere-JDBC 定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库&#x…...

cmake 项目。qt5升级 qt6 报错 error: “Qt requires a C++17 compiler 已解决

日常项目开发中。需要对qt5升级到qt6 做cmake兼容配置&#xff0c;在编译中发现&#xff0c;有c 编译环境 报错 2>C:\Qt\6.5.3\msvc2019_64\include\QtCore/qcompilerdetection.h(1226,1): fatal error C1189: #error: "Qt requires a C17 compiler, and a suitable …...

Flutter Engine 编译

本地环境 Flutter 开发基本环境配置&#xff0c;SDK【】 MAC. M2芯片 git工具 python环境[MAC自带] xcode Chromium depot_tools depot_tools 是调试 Flutter 引擎的必备工具包&#xff0c;包含了 gclient、gn 和 ninja 等工具&#xff0c;这些在下面会用到&#xff01;…...

数据可视化在商业领域有哪些重要性?

数据可视化在商业领域的重要性体现在多个方面&#xff0c;它通过将复杂的数据集转化为直观、易于理解的图形和图表&#xff0c;帮助企业和组织做出更明智的决策。以下是数据可视化对商业的一些关键重要性&#xff1a; 提高决策效率&#xff1a;通过直观的图表和图形&#xff0c…...

UI风格汇:扁平化风格来龙去脉,特征与未来趋势

Hello&#xff0c;我是大千UI工场&#xff0c;设计风格是我们新开辟的栏目&#xff0c;主要讲解各类UI风格特征、辨识方法、应用场景、运用方法等&#xff0c;本次带来的扁平化风格的解读&#xff0c;有设计需求&#xff0c;我们也可以接单。 一、什么是扁平化风格 扁平化风格…...

【雷达指标】MTI/MTD性能

目录 一、MTI/MTD性能的指标描述1.1 杂波衰减和对消比1.2 改善因子1.3 杂波中的可见度 二、MATLAB仿真参考文献 雷达通常使用MTI/MTD来进行杂波抑制&#xff0c;采用杂波衰减、对消比、改善因子、杂波中的可见度来描述其性能。 一、MTI/MTD性能的指标描述 1.1 杂波衰减和对消比…...

暴雨服务器:科技创新构建高效、高质、可持续的新质生产力

1月31日&#xff0c;中共中央政治局就扎实推进高质量发展进行第十一次集体学习。会议指出&#xff0c;发展新质生产力是推动高质量发展的内在要求和重要着力点&#xff0c;并系统概括了新质生产力的总体定义、动力来源、基本内涵、核心标志以及发展思路。这其中&#xff0c;新质…...

在 where子句中使用子查询(一)

目录 子查询返回单行单列 查询公司工资最低的员工信息 查找公司雇佣最早的员工信息 子查询返回单行多列 查询与 ALLEN 工资相同&#xff0c;职位相同的所有员工信息 子查询返回多行单列 IN 操作 查询职位是“MANAGER”的所有员工的薪水 Oracle从入门到总裁:https://bl…...

kafka为什么性能这么高?

Kafka系统架构 Kafka是一个分布式流处理平台&#xff0c;具有高性能和可伸缩性的特点。它使用了一些关键的设计原则和技术&#xff0c;以实现其高性能。 上图是Kafka的架构图&#xff0c;Producer生产消息&#xff0c;以Partition的维度&#xff0c;按照一定的路由策略&#x…...

安卓OpenGL添加水印并录制(二)---抖音录制原理

文章目录 前文回顾音频处理留个小思考总结 本文首发地址 https://h89.cn/archives/146.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 源码地址: Gitee: OpenGLRecorder 通过 前文 我们知道了如何采集 Camera 视频&#xff0c;叠加水印、贴纸保存为MP4&#xff0c;…...

动态绑定样式,uniapp,用三元运算动态绑定多个class类样式,动态绑定的样式可以和原始样式共存

介绍 | uni-app官网 vue、uniapp中动态添加绑定style、class 9种方法实现_vue style动态绑定-CSDN博客 uniapp使用三元运算符动态绑定元素的style样式_uniapp style动态绑定-CSDN博客 对象写法,可以写多个class类 class类的名字&#xff1a;判断条件&#xff0c;最后结果只有…...

神经网络基础——激活函数的选择、参数初始化

一、神经网络 1、神经网络 人工神经网络&#xff08;Artificial Neural Network&#xff0c;即ANN&#xff09;也简称为神经网络&#xff08;NN&#xff09;是一种模仿生物神经网络结构 和功能的计算模型。 2、基本部分 输入层&#xff1a;输入 x 输出层&#xff1a;输出 y 隐…...

ElasticSearch之聚合aggs

写在前面 本文看下es的聚合相关内容。 1&#xff1a;什么是聚合 即&#xff0c;数据的统计分析。如sum&#xff0c;count&#xff0c;avg&#xff0c;min&#xff0c;max&#xff0c;分组等。 2&#xff1a;支持哪些聚合类型 2.1&#xff1a;bucket aggregation 对满足特…...

Android 系统定位和高德定位

文章目录 Android 系统定位和高德定位系统定位工具类封装LocationManager使用 高德定位封装高德地图使用 Android 系统定位和高德定位 系统定位 工具类 public class LocationUtils {public static final int REQUEST_LOCATION 0xa1;/*** 判断定位服务是否开启*/public sta…...

Day20_网络编程(软件结构,网络编程三要素,UDP网络编程,TCP网络编程)

文章目录 Day20 网络编程学习目标1 软件结构2 网络编程三要素2.1 IP地址和域名1、IP地址2、域名3、InetAddress类 2.2 端口号2.3 网络通信协议1、OSI参考模型和TCP/IP参考模型2、UDP协议3、TCP协议 2.4 Socket编程 3 UDP网络编程3.1 DatagramSocket和DatagramPacket1、Datagram…...

https://registry.npm.taobao.org淘宝npm镜像仓库地址更新

在工作中有遇见获取淘宝的npm镜像存在问题&#xff0c;图示如下的报错&#xff1a; 根据报错的内容是说 https://registry.npm.taobao.org地址访问失败了&#xff0c;然后通过排查发现淘宝的npm镜像仓库地址有更新了。需要使用最新的地址 旧的淘宝镜像仓库&#xff1a;https://…...

离散数学(一) 集合

属于关系 表示 枚举法&#xff1b; 叙述法&#xff1b; 文氏图法 基数 空集 全集 全集是相对唯一的 相等关系 有相同元素看作一个元素 包含关系 幂集 集合运算 并集 交集 补集 差集 对称差集 定理 可数集合与不可数集合 自然数集 等势 如果存在集合A到集合B的双射(又称一一…...

IOS不使用默认的mainStroryboard作为首个controller的方法

步骤1&#xff1a; 删除info.plist文件下的一条配置&#xff0c;如图 步骤2&#xff1a; 编辑AppDelegate.m&#xff0c;参考以下代码 interface AppDelegate () //property (strong, nonatomic) UIWindow * window; property(nonatomic,strong) UIWindow * win; property(…...

Qt(C++)面试题 | 精选25项常问

面试是每个求职者都必须经历的一关,而QT面试更是需要面试者有深厚的编程基础和丰富的实战经验。下面我们为大家整理了25道QT面试题,希望能够帮助大家在求职路上获得成功。 ​Qt 中常用的五大模块是哪些? Qt 中常用的五大模块包括: QtCore:提供了 Qt 的核心功能,例如基本的…...

个人博客系列-环境配置-gitee(2)

注册gitee账户 地址&#xff1a;https://gitee.com/ 此步骤省略 新建仓库 执行以下命令 即可 拉取代码 创建目录 mkdir myCode && cd myCode 登录gitee找到项目&#xff0c;点击克隆&#xff0c;拉取代码 连接远程仓库命令 git remote add origin 仓库地址http…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...