分库分表-ShardingSphere 4.x(1)
最佳答案 问答题库788位专家为你答疑解惑
文章目录
- 分库分表-ShardingSphere 4.x(1)
- ShardingSphere概述
- Sharding-JDBC实战教程(上)
- Sharding-JDBC分库分表(⭐)
- 必备环境(数据库和SpringBoot项目⭐)
- 数据库(orderdb1和orderdb2),内容都为如下
- Pom.xml
- OrderMapper.class(mapper接口)
- Order.class(实体类)
- ShardingSphereApplication(SpringBoot启动类)
- 实战1:使用shardingsphere代理JDBC数据源操作数据库(不分库、不分表)
- application.properties
- junit测试类
- 测试1:插入10条记录
- 测试2:查询所有数据
- 实战2:使用shardingsphere操作数据库(inline策略分表、但是不分库)⭐
- application.properties
- junit测试类
- 测试1:插入10条记录
- 测试2:查询所有数据
- 测试3:查询指定order_id的数据
- 实战3:使用shardingsphere操作数据库(inline策略分表、inline策略分库)⭐
- application.properties
- junit测试类
- 测试1:插入10条记录
- 测试2:查询所有数据
- 测试3:查询指定order_id的数据
- inline策略的缺点(不能使用between,否则会报错⭐)
- 实战4:使用shardingsphere操作数据库(standard策略分表、standard策略分库)⭐
- 自定义分片策略类(standard策略)
- MyStandardRangeTableAlgorithm类(自定义分表的standard策略的范围分片类)
- MyStandardPreciseTableAlgorithm类(自定义分表的standard策略的精准分片类)
- MyStandardRangeDataBaseAlgorithm类(自定义分数据库的standard策略的范围分片类)
- MyStandardPreciseDataBaseAlgorithm类(自定义分数据库的standard策略的精准分片类)
- application.properties
- junit测试类
- 测试1:插入10条记录
- 测试2:查询指定order_id的数据
- 测试3:使用between范围查询,测试inline和standard的区别(inline策略会报错,但是standard策略不会)⭐
- 实战5:使用shardingsphere操作数据库(complex策略分表、complex策略分库)⭐
- 自定义分片策略类(complex策略)
- MyComplexTableAlgorithm类(自定义分表的complex策略的分片类)
- MyComplexDataBaseAlgorithm类(自定义分数据库的complex策略的分片类)
- application.properties
- junit测试类
- 测试1:查询指定order_id和user_id的数据(并且order_id和user_id同时都是分片键)⭐
- 实战6:使用shardingsphere操作数据库(hint策略分表、hint策略分库)⭐
- 自定义分片策略类(Hint策略)
- MyHintTableAlgorithm(自定义分表的Hint策略的分片类)
- MyHintDataBaseAlgorithm(自定义分数据库的Hint策略的分片类)
- application.properties
- junit测试类
- 测试1:根据hint策略进行强制分库分表插入数据到ds1的order_2表⭐
- 测试2:利用Hint策略查询ds1的order_2表⭐
分库分表-ShardingSphere 4.x(1)
项目所在仓库
ShardingSphere概述
Apache ShardingSphere 是一款开源的分布式数据库生态项目,由 JDBC 和 Proxy 两款产品组成。 其核心采用可插拔架构,通过组件扩展功能。 对上以数据库协议及 SQL 方式提供诸多增强功能,包括数据分片、访问路由、数据安全等;对下原生支持 MySQL、PostgreSQL、SQL Server、Oracle 等多种数据存储引擎。 Apache ShardingSphere 项目理念,是提供数据库增强计算服务平台,进而围绕其上构建生态。 充分利用现有数据库的计算与存储能力,通过插件化方式增强其核心能力,为企业解决在数字化转型中面临的诸多使用难点,为加速数字化应用赋能。
Sharding-JDBC实战教程(上)
ShardingSphere-JDBC 是 Apache ShardingSphere 的第一个产品,也是 Apache ShardingSphere 的前身。 它定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
ShardingSphere-JDBC 的优势在于极致性能和对 Java 应用的友好度。
Sharding-JDBC分库分表(⭐)
必备环境(数据库和SpringBoot项目⭐)
数据库(orderdb1和orderdb2),内容都为如下
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (`order_id` bigint(20) NOT NULL,`order_info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`user_id` bigint(20) NOT NULL,PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;DROP TABLE IF EXISTS `order_1`;
CREATE TABLE `order_1` (`order_id` bigint(20) NOT NULL,`order_info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`user_id` bigint(20) NOT NULL,PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;DROP TABLE IF EXISTS `order_2`;
CREATE TABLE `order_2` (`order_id` bigint(20) NOT NULL,`order_info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`user_id` bigint(20) NOT NULL,PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;DROP TABLE IF EXISTS `t_config`;
CREATE TABLE `t_config` (`config_id` bigint(20) NOT NULL,`config_info` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL,PRIMARY KEY (`config_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>ShardingSphere-Demo</artifactId><version>1.0-SNAPSHOT</version><properties>
<!-- springboot版本--><spring-boot.version>2.5.9</spring-boot.version><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- springboot-web依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- jdbc依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- mybatis-plus依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!-- 要使用下面这个druid依赖,不能使用druid-spring-boot-starter的依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.6</version></dependency><!-- shardingsphere-jdbc 依赖(最核心的依赖)--><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><!-- 单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency></dependencies><build><!-- 生成的jar包就是mytest.jar--><finalName>ShardingSphere</finalName><plugins><!-- 配置maven插件--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><phase>package</phase><goals><goal>repackage</goal></goals></execution></executions><!-- 版本需要指定为你当前springboot版本--><version>${spring-boot.version}</version><configuration><includeSystemScope>true</includeSystemScope><!-- 指定主类,也就是springboot启动类--><mainClass>com.boot.ShardingSphereApplication</mainClass></configuration></plugin></plugins></build></project>
OrderMapper.class(mapper接口)
package com.boot.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.boot.entity.Order;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;@Mapper
@Repository
public interface OrderMapper extends BaseMapper<Order> {}
Order.class(实体类)
package com.boot.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.io.Serializable;/*** TODO: 2022/8/2* @author youzhengjie*///lombok注解简化开发
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true) //开启链式编程
//由于mybatis-plus是在mybatis的基础上建立的,所以也有下面的通病(就是order本身就是关键字,无法被解析,所以需要加上``符号)。
//如果不加上@TableName指定表名,默认的表名就是该类的名称。
@TableName("`order`")
public class Order implements Serializable {@TableField("order_id")private Long orderId; //订单id@TableField("order_info")private String orderInfo; //订单信息@TableField("user_id")private Long userId; //用户id
}
ShardingSphereApplication(SpringBoot启动类)
package com.boot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ShardingSphereApplication {public static void main(String[] args) {SpringApplication.run(ShardingSphereApplication.class,args);}
}
实战1:使用shardingsphere代理JDBC数据源操作数据库(不分库、不分表)
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1#配置ds1的数据源(可以配置多个)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207
junit测试类
测试1:插入10条记录
@Testvoid addOrder(){for (int i = 0; i < 10; i++) {Order order = new Order();order.setOrderId(Long.parseLong(""+(i+1))).setOrderInfo("订单信息"+(i+1)).setUserId(Long.parseLong(""+(1001+i)));System.out.println(order);orderMapper.insert(order);}}
- 查看数据库:
测试2:查询所有数据
@Testvoid selectOrderList(){List<Order> orders = orderMapper.selectList(null);orders.forEach(System.out::println);}
实战2:使用shardingsphere操作数据库(inline策略分表、但是不分库)⭐
效果是:插入的数据如果order_id是奇数则会分到order_2表,偶数会分到order_1表(数据所在的数据库都为orderdb1,因为我们暂时没有分库)
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1#配置ds1的数据源(可以配置多个)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207# 真实数据节点配置,采用Groovy表达式(这里就代表我们可以操作的节点有ds1.order_1和ds1.order_2两个表)
spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds1.order_$->{1..2}# 主键id生成策略。
# 指定主键列,shardingsphere会为这个主键列自动生成id
spring.shardingsphere.sharding.tables.order.key-generator.column=order_id
# 生成主键的算法(推荐使用雪花算法)
spring.shardingsphere.sharding.tables.order.key-generator.type=snowflake# 开始正式的使用inline策略进行分表(缺点是这个策略会对mysql的BETWEEN AND、>、 <、 >=、 <= 操作失效!)-----分表。
# 指定一个分片键(这里指定指定一个)
spring.shardingsphere.sharding.tables.order.table-strategy.inline.sharding-column=order_id
# 分片算法(表达式)
spring.shardingsphere.sharding.tables.order.table-strategy.inline.algorithm-expression=order_$->{order_id % 2 + 1}#开启ShardingSphere的SQL输出日志
spring.shardingsphere.props.sql.show=true
# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 order_id ---> orderId
mybatis-plus.configuration.map-underscore-to-camel-case=true# 这个配置一定要加(注意)
spring.main.allow-bean-definition-overriding= true
junit测试类
测试1:插入10条记录
//根据inline策略进行分表,但是不分库@Testvoid addOrderByinlineShardingTable(){for (int i = 0; i < 10; i++) {Order order = new Order();//orderid不需要自己手动插入了!order.setOrderInfo("订单信息"+(i+1)).setUserId(Long.parseLong(""+(1001+i)));orderMapper.insert(order);}}
- 查看输出日志:
- 查看数据库:
测试2:查询所有数据
//查询全部数据@Testvoid selectAllByinlineShardingTable(){List<Order> orders = orderMapper.selectList(null);orders.forEach(System.out::println);}
- 查看输出日志:
测试3:查询指定order_id的数据
//查询指定order_id的数据@Testvoid selectOrderByinlineShardingTable_orderid(){QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.eq("order_id",762459329767931905L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
- 输出日志:
实战3:使用shardingsphere操作数据库(inline策略分表、inline策略分库)⭐
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1,ds2#配置ds1的数据源(对应orderdb1数据库)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207#配置ds2的数据源(对应orderdb2数据库)
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://localhost:3306/orderdb2?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=18420163207# 真实数据节点配置,采用Groovy表达式(这里就代表我们可以操作的节点有ds1.order_1和ds1.order_2和ds2.order_1和ds2.order_2四张表)
spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds$->{1..2}.order_$->{1..2}# 主键id生成策略。
# 指定主键列,shardingsphere会为这个主键列自动生成id
spring.shardingsphere.sharding.tables.order.key-generator.column=order_id
# 生成主键的算法(推荐使用雪花算法)
spring.shardingsphere.sharding.tables.order.key-generator.type=snowflake# 开始正式的使用inline策略进行分表(缺点是这个策略会对mysql的BETWEEN AND、>、 <、 >=、 <= 操作失效!)-----分表。
# 指定一个分片键(这里指定指定一个)
spring.shardingsphere.sharding.tables.order.table-strategy.inline.sharding-column=order_id
# 表的分片算法(表达式),下面这种算法会操作表的浪费,只有ds1.order_1和ds2.order_2才被使用,其他都被浪费
spring.shardingsphere.sharding.tables.order.table-strategy.inline.algorithm-expression=order_$->{order_id % 2 + 1}# 开始正式的使用inline策略进行分库(缺点是这个策略会对mysql的BETWEEN AND、>、 <、 >=、 <= 操作失效!)------分库。
# 指定一个分片键(这里指定指定一个)
spring.shardingsphere.sharding.tables.order.database-strategy.inline.sharding-column=order_id
# 数据库的分片算法(表达式)
spring.shardingsphere.sharding.tables.order.database-strategy.inline.algorithm-expression=ds$->{order_id % 2 + 1}#开启ShardingSphere的SQL输出日志
spring.shardingsphere.props.sql.show=true
# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 order_id ---> orderId
mybatis-plus.configuration.map-underscore-to-camel-case=true# 这个配置一定要加(注意)
spring.main.allow-bean-definition-overriding= true
junit测试类
测试1:插入10条记录
//根据inline策略进行分库和分表@Testvoid addOrderByinlineShardingTableAndDatabase(){for (int i = 0; i < 10; i++) {Order order = new Order();order.setOrderInfo("订单信息"+(i+1)).setUserId(Long.parseLong(""+(1001+i)));orderMapper.insert(order);}}
- 输出日志:
- 查看数据库:
测试2:查询所有数据
//查询全部数据@Testvoid selectAllByinlineShardingTableAndDatabase(){List<Order> orders = orderMapper.selectList(null);orders.forEach(System.out::println);}
- 输出日志:
测试3:查询指定order_id的数据
//查询指定order_id的数据@Testvoid selectOrderByinlineShardingTableAndDatabase_orderid(){QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.eq("order_id",762681526788816896L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
- 输出日志:
inline策略的缺点(不能使用between,否则会报错⭐)
//查询order_id在一个范围的数据@Testvoid selectOrderByinlineShardingTableAndDatabase_between(){QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.between("order_id",762681526704930816L,862681526830759936L);//lt是小于、gt是大于,这些inline策略都是不支持的
// objectQueryWrapper.lt("order_id",762681526704930816L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
- 这里我们使用了between,由于between是范围查询,而inline策略是不支持这种查询的,所以会报错。
- 解决方法:就是使用其他分片策略,比如下面的standard/complex/Hint这些。(这些策略提供了精确分片和范围分片)
实战4:使用shardingsphere操作数据库(standard策略分表、standard策略分库)⭐
自定义分片策略类(standard策略)
MyStandardRangeTableAlgorithm类(自定义分表的standard策略的范围分片类)
package com.boot.algorithm.standard.range;import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** 该类适用于BETWEEN AND、>、 <、 >=、 <= 操作*///1:MyStandardRangeTableAlgorithm:自定义分表的standard策略的范围分片类
//2:RangeShardingAlgorithm接口的泛型是分片键的类型(我们的分片键是order_id它是Long类型的所以就是Long)
public class MyStandardRangeTableAlgorithm implements RangeShardingAlgorithm<Long> {/*** 由于是范围分片,所以返回的是一个集合(集合里面的值是表名)*/@Overridepublic Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {//例如sql:select * from order where order_id between 200 and 300String logicTableName = rangeShardingValue.getLogicTableName(); //逻辑表名:也就是orderString columnName = rangeShardingValue.getColumnName(); //分片键:也就是order_idLong lowerEndpoint = rangeShardingValue.getValueRange().lowerEndpoint(); //between的最小值:在上面的sql就是200Long upperEndpoint = rangeShardingValue.getValueRange().upperEndpoint(); //between的最大是:在上面的sql就是300List<String> tables = new ArrayList<>(); //需要sharding-jdbc查询的表//由于这里是range范围查询,所以要查询全部表,所以要把所有表名添加到集合中tables.add(logicTableName+"_1"); //表名:order_1tables.add(logicTableName+"_2"); //表名:order_2return tables;}}
MyStandardPreciseTableAlgorithm类(自定义分表的standard策略的精准分片类)
package com.boot.algorithm.standard.precise;import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;import java.math.BigInteger;
import java.util.Collection;/**
* 该类适用于=、in操作
*///1:MyStandardPreciseTableAlgorithm:自定义分表的standard策略的精准分片类
//2:PreciseShardingAlgorithm接口的泛型是分片键的类型(我们的分片键是order_id它是Long类型的所以就是Long)
public class MyStandardPreciseTableAlgorithm implements PreciseShardingAlgorithm<Long> {/*** 由于是精准分片,所以返回的是一个字符串(字符串就是指定的表名)* @param collection 真实表名集合。order_1和order_2*/@Overridepublic String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {//例如sql:select * from order where order_id=201String logicTableName = preciseShardingValue.getLogicTableName(); //逻辑表名。也就是orderString columnName = preciseShardingValue.getColumnName(); //分片键名。也就是order_idLong columnvalue = preciseShardingValue.getValue(); //分片键的值。比如上面的sql,那么这个value就是201//实现order_$->{order_id % 2 + 1} 分片算法BigInteger bigInteger = BigInteger.valueOf(columnvalue);BigInteger tableNumber = bigInteger.mod(new BigInteger("2")).add(new BigInteger("1"));//最终需要查询的表名String tableName=logicTableName+"_"+tableNumber; //如果tableNumber是1,那么tableName就是order_1//判断我们计算出来的表名是否存在if(collection.contains(tableName)){return tableName; //返回指定的表名}throw new UnsupportedOperationException("MyStandardPreciseTableAlgorithm没有找到指定的表名");}}
MyStandardRangeDataBaseAlgorithm类(自定义分数据库的standard策略的范围分片类)
package com.boot.algorithm.standard.range;import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/**
* 该类适用于BETWEEN AND、>、 <、 >=、 <= 操作
*/// MyStandardRangeDataBaseAlgorithm:自定义分数据库的standard策略的范围分片类
public class MyStandardRangeDataBaseAlgorithm implements RangeShardingAlgorithm<Long> {/*** 由于是范围分片,所以返回的是一个集合(集合里面的值是数据源名)*/@Overridepublic Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {List<String> dataSources = new ArrayList<>(); //数据源名称集合//由于这里是范围查询,所以全部数据源都要查询,故把所有数据源名称添加进去dataSources.add("ds1");dataSources.add("ds2");return dataSources;}
}
MyStandardPreciseDataBaseAlgorithm类(自定义分数据库的standard策略的精准分片类)
package com.boot.algorithm.standard.precise;import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;import java.math.BigInteger;
import java.util.Collection;/**
* 该类适用于=、in操作
*/// MyStandardPreciseDataBaseAlgorithm:自定义分数据库的standard策略的精准分片类
public class MyStandardPreciseDataBaseAlgorithm implements PreciseShardingAlgorithm<Long> {/**** collection存储了所有表名。ds1和ds2* @return*/@Overridepublic String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {//实现ds$->{order_id % 2 + 1}算法Long value = preciseShardingValue.getValue();//拿到分片键的值。也就是order_id的值BigInteger bigInteger = BigInteger.valueOf(value);BigInteger dataSourceNumber = bigInteger.mod(new BigInteger("2")).add(new BigInteger("1"));//最终查询的数据源名称String dataSourceName="ds"+dataSourceNumber; //ds1或者ds2if (collection.contains(dataSourceName)) { //判断dataSourceName是否真实存在return dataSourceName;}throw new UnsupportedOperationException("MyStandardPreciseDataBaseAlgorithm没有找到指定数据源名称");}
}
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1,ds2#配置ds1的数据源(对应orderdb1数据库)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207#配置ds2的数据源(对应orderdb2数据库)
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://localhost:3306/orderdb2?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=18420163207# 真实数据节点配置,采用Groovy表达式(这里就代表我们可以操作的节点有ds1.order_1和ds1.order_2和ds2.order_1和ds2.order_2四张表)
spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds$->{1..2}.order_$->{1..2}# 主键id生成策略。
# 指定主键列,shardingsphere会为这个主键列自动生成id
spring.shardingsphere.sharding.tables.order.key-generator.column=order_id
# 生成主键的算法(推荐使用雪花算法)
spring.shardingsphere.sharding.tables.order.key-generator.type=snowflake# 开始正式的使用standard策略进行分表-----分表。
# 指定一个分片键(这里指定指定一个)
spring.shardingsphere.sharding.tables.order.table-strategy.standard.sharding-column=order_id
# 指定范围分片的自定义类的全类名 (比如BETWEEN AND、>、 <、 >=、 <= 操作就是范围分片)
spring.shardingsphere.sharding.tables.order.table-strategy.standard.range-algorithm-class-name=com.boot.algorithm.standard.range.MyStandardRangeTableAlgorithm
# 指定精准分片的自定义类的全类名 (比如=、in就是精准分片)
spring.shardingsphere.sharding.tables.order.table-strategy.standard.precise-algorithm-class-name=com.boot.algorithm.standard.precise.MyStandardPreciseTableAlgorithm# 开始正式的使用standard策略进行分库------分库。
# 指定一个分片键(这里指定指定一个)
spring.shardingsphere.sharding.tables.order.database-strategy.standard.sharding-column=order_id
# 指定范围分片的自定义类的全类名 (比如BETWEEN AND、>、 <、 >=、 <= 操作就是范围分片)
spring.shardingsphere.sharding.tables.order.database-strategy.standard.range-algorithm-class-name=com.boot.algorithm.standard.range.MyStandardRangeDataBaseAlgorithm
# 指定精准分片的自定义类的全类名 (比如=、in就是精准分片)
spring.shardingsphere.sharding.tables.order.database-strategy.standard.precise-algorithm-class-name=com.boot.algorithm.standard.precise.MyStandardPreciseDataBaseAlgorithm#开启ShardingSphere的SQL输出日志
spring.shardingsphere.props.sql.show=true
# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 order_id ---> orderId
mybatis-plus.configuration.map-underscore-to-camel-case=true# 这个配置一定要加(注意)
spring.main.allow-bean-definition-overriding= true
junit测试类
测试1:插入10条记录
//根据standard策略进行分库和分表@Testvoid addOrderBystandardShardingTableAndDatabase(){for (int i = 0; i < 10; i++) {Order order = new Order();order.setOrderInfo("订单信息"+(i+1)).setUserId(Long.parseLong(""+(1001+i)));orderMapper.insert(order);}}
测试2:查询指定order_id的数据
//查询指定order_id的数据@Testvoid selectOrderBystandardShardingTableAndDatabase_orderid(){QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.eq("order_id",763033347873046528L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
测试3:使用between范围查询,测试inline和standard的区别(inline策略会报错,但是standard策略不会)⭐
//查询order_id在一个范围的数据(inline策略会报错)@Testvoid selectOrderByStandardShardingTableAndDatabase_between(){QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.between("order_id",762681526704930816L,862681526830759936L);//lt是小于、gt是大于,这些inline策略都是不支持的
// objectQueryWrapper.lt("order_id",762681526704930816L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
- 测试结果:(standard策略不会报错。)
实战5:使用shardingsphere操作数据库(complex策略分表、complex策略分库)⭐
自定义分片策略类(complex策略)
MyComplexTableAlgorithm类(自定义分表的complex策略的分片类)
package com.boot.algorithm.complex;import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;import java.math.BigInteger;
import java.util.*;public class MyComplexTableAlgorithm implements ComplexKeysShardingAlgorithm<Long> {//collection存储了所有表名@Overridepublic Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {//select * from order where order_id between 663033347873046528L and 763033347873046528L and user_id=1003String logicTableName = complexKeysShardingValue.getLogicTableName(); //逻辑表名//getColumnNameAndRangeValuesMap方法:获取范围(between、>、<)的分片键。(相当于standard策略的范围分片类)Range<Long> orderIdRange = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("order_id");//如果我们的sql没有写between and或者其他范围相关的操作符,则orderIdRange就会空,调用下面的Endpoint方法就会NullPointerException。//所以一定要进行如下判断if(orderIdRange!=null&&orderIdRange.isEmpty()){Long lowerEndpoint = orderIdRange.lowerEndpoint(); //663033347873046528LLong upperEndpoint = orderIdRange.upperEndpoint(); //763033347873046528L}//getColumnNameAndShardingValuesMap方法:获取精准(=、in)的分片键。(相当于standard策略的精准分片类)Collection<Long> userIdCol = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("user_id");//如果我们的sql没有写=或者in,则userIdCol就会空,那么下面遍历这个集合就会NullPointerException//所以一定要进行如下判断.//如果userIdCol不为null,则遍历这个集合,实现order_$->{order_id % 2 + 1}算法if (userIdCol!=null&&!userIdCol.isEmpty()) {//最终查询的表名集合,因为=和in可能有多个值。List<String> tables = new ArrayList<>();//这里虽然是集合,但是我们很多情况下可以把它想成只有一个元素。for (Long value : userIdCol) {BigInteger bigInteger = BigInteger.valueOf(value);BigInteger tableNumber = bigInteger.mod(new BigInteger("2")).add(new BigInteger("1"));String tableName=logicTableName+"_"+tableNumber;if(collection.contains(tableName)){tables.add(tableName); //添加到集合中}else {throw new UnsupportedOperationException("MyComplexTableAlgorithm没有该表名");}}System.out.println(tables);return tables;}else { //如果userIdCol集合为null,那么就相当于范围查询,则查询全部表return collection; //collection里面有全部表名}}}
MyComplexDataBaseAlgorithm类(自定义分数据库的complex策略的分片类)
package com.boot.algorithm.complex;import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;public class MyComplexDataBaseAlgorithm implements ComplexKeysShardingAlgorithm<Long> {//collection存储了全部数据源名称@Overridepublic Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {//getColumnNameAndRangeValuesMap方法:获取范围(between、>、<)的分片键。(相当于standard策略的范围分片类)Range<Long> orderIdRange = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("order_id");//如果我们的sql没有写between and或者其他范围相关的操作符,则orderIdRange就会空,调用下面的Endpoint方法就会NullPointerException。//所以一定要进行如下判断if(orderIdRange!=null&&orderIdRange.isEmpty()){Long lowerEndpoint = orderIdRange.lowerEndpoint(); //663033347873046528LLong upperEndpoint = orderIdRange.upperEndpoint(); //763033347873046528L}//getColumnNameAndShardingValuesMap方法:获取精准(=、in)的分片键。(相当于standard策略的精准分片类)Collection<Long> userIdCol = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("user_id");//如果我们的sql没有写=或者in,则userIdCol就会空,那么下面遍历这个集合就会NullPointerException//所以一定要进行如下判断。//如果userIdCol不为null,则遍历这个集合,实现ds$->{order_id % 2 + 1}算法。if (userIdCol!=null&&!userIdCol.isEmpty()) {//最终查询的表名集合,因为=和in可能有多个值。List<String> datasouces = new ArrayList<>();//这里虽然是集合,但是我们很多情况下可以把它想成只有一个元素。for (Long value : userIdCol) {BigInteger bigInteger = BigInteger.valueOf(value);BigInteger dataSourceNumber = bigInteger.mod(new BigInteger("2")).add(new BigInteger("1"));String dataSourceName="ds"+dataSourceNumber;if(collection.contains(dataSourceName)){datasouces.add(dataSourceName); //添加到集合中}else {throw new UnsupportedOperationException("MyComplexDataBaseAlgorithm没有该数据源名");}}return datasouces;}else { //如果userIdCol集合为null,那么就相当于范围查询,则查询全部数据源return collection; //collection里面有全部数据源名称}}
}
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1,ds2#配置ds1的数据源(对应orderdb1数据库)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207#配置ds2的数据源(对应orderdb2数据库)
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://localhost:3306/orderdb2?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=18420163207# 真实数据节点配置,采用Groovy表达式(这里就代表我们可以操作的节点有ds1.order_1和ds1.order_2和ds2.order_1和ds2.order_2四张表)
spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds$->{1..2}.order_$->{1..2}# 主键id生成策略。
# 指定主键列,shardingsphere会为这个主键列自动生成id
spring.shardingsphere.sharding.tables.order.key-generator.column=order_id
# 生成主键的算法(推荐使用雪花算法)
spring.shardingsphere.sharding.tables.order.key-generator.type=snowflake# 开始正式的使用complex策略进行分表-----分表。
# 指定一个或多个分片键(这里的分片键指定为order_id和user_id)
spring.shardingsphere.sharding.tables.order.table-strategy.complex.sharding-columns=order_id,user_id
# 指定complex分片的自定义类的全类名
spring.shardingsphere.sharding.tables.order.table-strategy.complex.algorithm-class-name=com.boot.algorithm.complex.MyComplexTableAlgorithm# 开始正式的使用complex策略进行分库------分库。
# 指定一个或多个分片键(这里的分片键指定为order_id和user_id)
spring.shardingsphere.sharding.tables.order.database-strategy.complex.sharding-columns=order_id,user_id
# 指定complex分片的自定义类的全类名
spring.shardingsphere.sharding.tables.order.database-strategy.complex.algorithm-class-name=com.boot.algorithm.complex.MyComplexDataBaseAlgorithm#开启ShardingSphere的SQL输出日志
spring.shardingsphere.props.sql.show=true
# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 order_id ---> orderId
mybatis-plus.configuration.map-underscore-to-camel-case=true# 这个配置一定要加(注意)
spring.main.allow-bean-definition-overriding= true
junit测试类
测试1:查询指定order_id和user_id的数据(并且order_id和user_id同时都是分片键)⭐
//查询指定order_id和user_id的数据(并且order_id和user_id同时都是分片键)@Testvoid selectOrderBystandardShardingTableAndDatabase_orderidAndUserid(){//select * from order where order_id between 663033347873046528L and 763033347873046528L and user_id=1003QueryWrapper<Order> objectQueryWrapper = new QueryWrapper<>();objectQueryWrapper.between("order_id",663033347873046528L,763033347873046528L);objectQueryWrapper.eq("user_id",1003L);List<Order> orders = orderMapper.selectList(objectQueryWrapper);orders.forEach(System.out::println);}
实战6:使用shardingsphere操作数据库(hint策略分表、hint策略分库)⭐
自定义分片策略类(Hint策略)
MyHintTableAlgorithm(自定义分表的Hint策略的分片类)
package com.boot.algorithm.hint;import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;//HintShardingAlgorithm的泛型就是addTableShardingValue方法的value的类型(我们通常使用Integer)
public class MyHintTableAlgorithm implements HintShardingAlgorithm<Integer> {@Overridepublic Collection<String> doSharding(Collection<String> collection, HintShardingValue<Integer> hintShardingValue) {List<String> tables = new ArrayList<>();String tableName="order_"+hintShardingValue.getValues().toArray()[0];if(collection.contains(tableName)){tables.add(tableName);return tables;}throw new UnsupportedOperationException("MyHintTableAlgorithm没有找到表名");}
}
MyHintDataBaseAlgorithm(自定义分数据库的Hint策略的分片类)
package com.boot.algorithm.hint;import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;//HintShardingAlgorithm的泛型就是addDatabaseShardingValue方法的value的类型(我们通常使用Integer)
public class MyHintDataBaseAlgorithm implements HintShardingAlgorithm<Long> {@Overridepublic Collection<String> doSharding(Collection<String> collection, HintShardingValue<Long> hintShardingValue) {List<String> datasources = new ArrayList<>();String dataSourceName="ds"+hintShardingValue.getValues().toArray()[0];if(collection.contains(dataSourceName)){datasources.add(dataSourceName);return datasources;}throw new UnsupportedOperationException("MyHintDataBaseAlgorithm没有找到数据源名");}
}
application.properties
#配置ShardingSphere数据源,定义一个或多个数据源名称
spring.shardingsphere.datasource.names=ds1,ds2#配置ds1的数据源(对应orderdb1数据库)
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/orderdb1?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=18420163207#配置ds2的数据源(对应orderdb2数据库)
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://localhost:3306/orderdb2?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=18420163207# 真实数据节点配置,采用Groovy表达式(这里就代表我们可以操作的节点有ds1.order_1和ds1.order_2和ds2.order_1和ds2.order_2四张表)
spring.shardingsphere.sharding.tables.order.actual-data-nodes=ds$->{1..2}.order_$->{1..2}# 主键id生成策略。
# 指定主键列,shardingsphere会为这个主键列自动生成id
spring.shardingsphere.sharding.tables.order.key-generator.column=order_id
# 生成主键的算法(推荐使用雪花算法)
spring.shardingsphere.sharding.tables.order.key-generator.type=snowflake# 开始正式的使用hint策略进行分表-----分表。
# 指定hint分片的自定义类的全类名
spring.shardingsphere.sharding.tables.order.table-strategy.hint.algorithm-class-name=com.boot.algorithm.hint.MyHintTableAlgorithm# 开始正式的使用hint策略进行分库------分库。
# 指定hint分片的自定义类的全类名
spring.shardingsphere.sharding.tables.order.database-strategy.hint.algorithm-class-name=com.boot.algorithm.hint.MyHintDataBaseAlgorithm#开启ShardingSphere的SQL输出日志
spring.shardingsphere.props.sql.show=true
# 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 order_id ---> orderId
mybatis-plus.configuration.map-underscore-to-camel-case=true# 这个配置一定要加(注意)
spring.main.allow-bean-definition-overriding= true
junit测试类
测试1:根据hint策略进行强制分库分表插入数据到ds1的order_2表⭐
@Testvoid addOrderByHintShardingTableAndDataBase(){HintManager hintManager = HintManager.getInstance();//实现指定操作ds1的order_2表hintManager.addDatabaseShardingValue("order",1);//添加分库的值为1hintManager.addTableShardingValue("order",2); //添加分表的值为2for (int i = 0; i < 10; i++) {Order order = new Order();//orderid不需要自己手动插入了!order.setOrderInfo("订单信息"+(i+1)).setUserId(Long.parseLong(""+(1001+i)));orderMapper.insert(order);}hintManager.close(); //用完之后要调用close方法。}
- 查询数据库
测试2:利用Hint策略查询ds1的order_2表⭐
@Testvoid selectAllByHintShardingTableAndDataBase(){HintManager hintManager = HintManager.getInstance();//实现指定操作ds1的order_2表hintManager.addDatabaseShardingValue("order",1);//添加分库的值为1hintManager.addTableShardingValue("order",2); //添加分表的值为2List<Order> orders = orderMapper.selectList(null);orders.forEach(System.out::println);hintManager.close(); //用完之后要调用close方法。}
- 输出日志:
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"分库分表-ShardingSphere 4.x(1)":http://eshow365.cn/6-25138-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!