使用ShardingSphere实现MySql的分库分表
目录
一 什么是ShardingSphere分库分表
二 代码实现
1.导入相关依赖
2.配置相关参数
3.创建学生类以及mapper接口
4.实现 StandardShardingAlgorithm接口自定义分片算法
唐洋洋我知道你在看!!!嘿嘿
一 什么是ShardingSphere分库分表
我们平时在设计数据库的时候,一般都是一个数据库里面有很多张表,比如用户表,那么所有的用户信息都会存在这一张表里面。但是当数据量特别大的时候,如果你只用一个数据库一张用户表来存,这样就会到这这个数据库访问压力过大。所以分库分表就是,把大量用户数据分成多个数据库的多张表来存,这里以学生信息表为例:
可以看到,我创建了两个数据库,每个数据库分别有两张表来存储学生信息,这样相当于一共有四张学生表了,这样就能减少每个数据库的访问压力。
既然分库分表的意思明白了,那么我们查询或者插入学生表的时候,该怎么操作呢?比如我现在要存入一个学生信息,我该往哪个表存呢?那么这里肯定是通过计算出来的,而且是某种算法,整体要平均。
所以这就是我们ShardingSphere的作用。
二 代码实现
1.导入相关依赖
<!-- shardingsphere依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>5.3.2</version>
<exclusions>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 坑爹的版本冲突 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
</dependency>
2.配置相关参数
application.yml参数:
spring:
datasource:
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
url: jdbc:shardingsphere:classpath:shardingsphere-config.yaml
shardingsphere-config.yaml参数:
dataSources:
student_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/student_0?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: 1234
student_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/student_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: 1234
rules:
- !SHARDING #分片规则
tables:
tb_student: #逻辑表名
actualDataNodes: student_${0..1}.t_student_${0..3}
databaseStrategy: # 分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: id # 分片列名称
shardingAlgorithmName: db_hash_mode_algorithm # 分片算法名称
tableStrategy: # 分表策略,同分库策略
standard: # 用于单分片键的标准分片场景
shardingColumn: id # 分片列名称
shardingAlgorithmName: tb_student_hash_mode_algorithm # 分片算法名称
# 分片算法配置
shardingAlgorithms:
db_hash_mode_algorithm:
type: CLASS_BASED # 分片算法类型 自定义
props: # 分片算法属性配置
db_sharding-count: 2
table_sharding-count: 4
strategy: standard #标准的分片算法
algorithmClassName: com.feisi.shardingsphere.MyStandardShardingAlgorithm
tb_student_hash_mode_algorithm:
type: HASH_MOD
props:
sharding-count: 4
props:
sql-show: true
3.创建学生类以及mapper接口
学生类:
package com.feisi.shardingsphere.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@TableName("tb_student")
@Builder
@Component
public class Student {
@TableId(type = IdType.INPUT)
private Long id; //分片键
private String name;
private Integer age;
}
学生mapper接口:
package com.feisi.shardingsphere.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.feisi.shardingsphere.pojo.Student;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StudentMapper extends BaseMapper<Student> {
}
4.实现 StandardShardingAlgorithm接口自定义分片算法
package com.feisi.shardingsphere;
import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.sharding.algorithm.sharding.ShardingAutoTableAlgorithmUtil;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.apache.shardingsphere.sharding.exception.algorithm.sharding.ShardingAlgorithmInitializationException;
import java.util.Collection;
import java.util.Optional;
import java.util.Properties;
public class MyStandardShardingAlgorithm implements StandardShardingAlgorithm<Comparable<?>> {
// 数据库的数量配置参数名
private static final String DB_SHARDING_COUNT_KEY = "db_sharding-count";
// 表的数量配置参数名
private static final String TABLE_SHARDING_COUNT_KEY = "table_sharding-count";
private int dbShardingCount;
private int tableShardingCount;
@Override
public void init(final Properties props) {
dbShardingCount = getDbShardingCount(props);
tableShardingCount = getTableShardingCount(props);
}
private int getTableShardingCount(Properties props) {
ShardingSpherePreconditions.checkState(props.containsKey(TABLE_SHARDING_COUNT_KEY), () -> new ShardingAlgorithmInitializationException(getType(), "Sharding count cannot be null."));
return Integer.parseInt(props.getProperty(TABLE_SHARDING_COUNT_KEY));
}
private int getDbShardingCount(Properties props) {
ShardingSpherePreconditions.checkState(props.containsKey(DB_SHARDING_COUNT_KEY), () -> new ShardingAlgorithmInitializationException(getType(), "Sharding count cannot be null."));
return Integer.parseInt(props.getProperty(DB_SHARDING_COUNT_KEY));
}
@Override
//availableTargetNames: ds_${0..1}: ds_0 ds_1
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Comparable<?>> shardingValue) {
//id进行hash 数据库数量 2 表的数量 4
// 这里使用哈希取余的算法
// hash % 4 = 0..3 /2 0,1 /2 = 0 2,3/2 = 1
String suffix = String.valueOf(hashShardingValue(shardingValue.getValue()) % tableShardingCount / dbShardingCount);
return ShardingAutoTableAlgorithmUtil.findMatchedTargetName(availableTargetNames, suffix, shardingValue.getDataNodeInfo()).orElse(null);
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Comparable<?>> shardingValue) {
return availableTargetNames;
}
//对分片键的值进行hash算法
private long hashShardingValue(final Object shardingValue) {
return Math.abs((long) shardingValue.hashCode());
}
@Override
public String getType() {
return "CLASS_BASED";
}
}
这里自定义分片算法在dosharding方法里面,分片算法的意思就是,根据你的分片建通过算法确定你的学生信息存储到哪个数据库中的哪张表里面去。
这里使用的是哈希取余算法,先根据你的分片键(这里的分片键就是id),计算出它的哈希值,然后:
哈希值%你的数据表的数量=要存的哪块表
要存的哪块表%你的数据库的数量=要存在哪个库里面。
为什么公式是这样的,因为我们的每个库从0开始,每个库对应下面的表也是从0开始。所以这个公式就能算出来。
比如一个id的哈希值是:448488114
我们的库数量是2个(0,1)
表数量是4个(0,1,2,3)
那么:448488114%4=2(存在表2里面)
但是表2在数据库1下面,所以你的算法不能算错,如果算到0库,那么就找不到这个张表了。
2/2=1(数据库1)
这样就完成了,最后算到你这个学生信息应该存到数据库1下面的数据表2中。