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

​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

转运机器人,AGV底盘小车:打造高效、精准的汽车电子生产线

为了满足日益增长的市场需求&#xff0c;保持行业领先地位&#xff0c;某汽车行业电子产品企业引入富唯智能AMR智能搬运机器人及其智能物流解决方案&#xff0c;采用自动化运输措施优化生产节拍和搬运效率&#xff0c;企业生产效率得到显著提升。 项目背景&#xff1a; 1、工厂…

【算法与数据结构】1971、LeetCode寻找图中是否存在路径

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题应用并查集的理论直接就可以解决&#xff1a;【算法与数据结构】回溯算法、贪心算法、动态规划、图…

深入浅出JVM(七)之执行引擎的解释执行与编译执行

本篇文章围绕执行引擎&#xff0c;深入浅出的解析执行引擎中解释器与编译器的解释执行和编译执行、执行引擎的执行方式、逃逸分析带来的栈上分配、锁消除、标量替换等优化以及即时编译器编译对热点代码的探测 执行引擎 hotspot执行引擎结构图 执行引擎分为解释器、JIT即时编译…

QT_day4

1.思维导图 2. 输入闹钟时间格式是小时:分钟 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);id startTimer(1000);flag1;speecher new QTextT…

做抖音小店怎么选品?给新手商家的三条建议,能让你销量猛增999+

大家好&#xff0c;我是电商花花。 总是担心店铺不出单&#xff0c;没有销量&#xff0c;看着断断续续的收益&#xff0c;新手商家应该都是愁容满面吧。 今天花花从是3个维度上给新手商家一些建议&#xff0c;讲解一下如何高效选品&#xff0c;加你如何让你出单猛增999。 以前…

训练Sora模型,你可能需要这些开源代码,模型,数据集及算力评估

在之前的文章&#xff0c;我们总结了Sora模型上用到的一些核心技术和论文 复刻大模型 Sora 有多难&#xff1f;一张图带你读懂 Sora 的技术路径一文看懂大模型 Sora 技术推演 今天这篇文章来自我们社区讨论交流&#xff0c;我这边整理和总结现有的一些开源代码、模型、数据集…

【大数据】Flink 内存管理(一):设置 Flink 进程内存

Flink 内存管理&#xff08;一&#xff09;&#xff1a;设置 Flink 进程内存 1.配置 Total Memory2.JVM 参数3.根据比例限制的组件&#xff08;Capped Fractionated Components&#xff09; Apache Flink 通过严格控制各种组件的内存使用&#xff0c;在 JVM 上提供高效的工作负…

【论文阅读】ICCV 2023 计算和数据高效后门攻击

文章目录 一.论文信息二.论文内容1.摘要2.引言3.主要图表4.结论 一.论文信息 论文题目&#xff1a; Computation and Data Efficient Backdoor Attacks&#xff08;计算和数据高效后门攻击&#xff09; 论文来源&#xff1a; 2023-ICCV&#xff08;CCF-A&#xff09; 论文团…

AI文生图网站测评

主要测评文章配图生成效果、绘制logo等效果 测评关键点&#xff1a;生成效果、网站易用度、是否免费 测评prompt&#xff1a;请生成一个文章内容配图&#xff0c;图片比例是3&#xff1a;2&#xff0c;文章主旨是AI既是机遇&#xff0c;也存在挑战和风险&#xff0c;要求图片…

Matlab/simulink基于vsg的风光储调频系统建模仿真(持续更新)

​ 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

leet hot 100-3 最长连续序列

两数之和 原题链接思路代码 原题链接 leet hot 100-3 128. 最长连续序列 思路 可以把所有的数字放到容器里面去 维护一个最大值 每一次去遍历数字 查看但当前数字是否为起始位置&#xff08;它的前面是否有比它小一位的数字&#xff09; 如果是起始位置 就记录一下当前值 并…

应用回归分析:泊松回归

泊松回归是一种广泛用于计数数据的回归分析方法。它适用于响应变量是非负整数的情况&#xff0c;特别是当这些计数呈现出明显的离散分布时。泊松回归通过泊松分布的概率分布函数来建模计数数据&#xff0c;使其成为处理计数数据的自然选择。本文将介绍泊松回归的基本概念、应用…

FastJson反序列化漏洞(Fastjson1.2.47)

一、FastJson Fastjson 是一个阿里巴巴公司开源的 Java 语言编写的高性能功能完善的 JSON 库。可以将Java 对象转换为 JSON 格式(序列化)&#xff0c;当然它也可以将 JSON 字符串转换为 Java 对象&#xff08;反序列化&#xff09; 它采用一种“假定有序快速匹配”的算法&…

【RAG实践】基于LlamaIndex和Qwen1.5搭建基于本地知识库的问答机器人

什么是RAG LLM会产生误导性的 “幻觉”&#xff0c;依赖的信息可能过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented G…

SpringBoot -【BeanPostProcessor】基础使用及应用场景

BeanPostProcessor应用与优化 1. 引言 在现代软件开发中&#xff0c;企业开发面临着越来越复杂的系统架构和业务需求。随着项目规模的扩大和技术栈的增多&#xff0c;需要更高效的工具来应对这些挑战&#xff0c;并确保代码的可维护性和扩展性。 在这样的背景下&#xff0c;Be…

第五章虚拟机栈

第五章虚拟机栈 文章目录 第五章虚拟机栈1. 虚拟机栈概述1.1 虚拟机栈出现的背景1.2 初步印象1.2.1 内存中的栈与堆 1.3 虚拟机栈基本内容1.3.1 Java虚拟机栈是什么&#xff1f;1.3.2 栈的特点(优点)1.3.3 栈中可能出现的异常1.3.4 设置栈内存大小 2. 栈的存储结构2.1 栈中存储…

安科瑞企业微电网智慧能源管理系统生态交流会顺利举行

2024年1月12日&#xff0c;安科瑞企业微电网智慧能源管理系统生态交流会顺利举行&#xff0c;本次会议旨在围绕双碳目标&#xff0c;共同探讨如何抓住新机遇、新市场&#xff0c;充分利用安科瑞企业微电网智慧能源的一站式服务&#xff0c;为企业节能、减碳、降本赋能&#xff…

第十一天-Excel的操作

目录 1.xlrd-Excel的读模块 安装 使用 获取工作簿 读取工作簿的内容 xlsxwriter-Excel的写模块 安装 使用 生成图表 add_series参数 图表的样式 demo&#xff1a;生成图表 Excel的操作在python中有多个模块&#xff0c;为了能够快速使用&#xff0c;选择了相对简单…

变分自编码器 VAE 超详解,从简单公式推导到模型结构到模型理解

参考文献&#xff1a; [1] Kingma D P, Welling M. Auto-encoding variational bayes[J]. arXiv preprint arXiv:1312.6114, 2013. [2] Doersch C. Tutorial on variational autoencoders[J]. arXiv preprint arXiv:1606.05908, 2016. [3] 变分自编码器&#xff08;一&#xff…

Linux学习方法-框架学习法——Linux应用程序编程框架

配套视频学习链接&#xff1a;https://www.bilibili.com/video/BV1HE411w7by?p4&vd_sourced488bc722b90657aaa06a1e8647eddfc 目录 Linux应用程序编程 Linux应用程序编程 Linux文件I/O(input/output) Linux文件I/O(五种I/O模型) Linux多进程 Linux多线程 网络通信(s…