shardingSphere

在这里插入图片描述

shardingSphere主要包含3个重要产品,shardingJDBC,sharding Proxy以及shardingsideCar(服务网格相关).
简单来说shardingsphere主要就是用来做分库分表的, 分库分表就是之前说的,select * from logs()//当mysql单表查询 500w以上的数据量
因为当表的数据量大于500w的时候 我做查询 或者我做过滤 的话查询效率就会很慢
我们此时可以吧数据进行分库分表,这个时候就用到分库分表 就是数据的分片存储,分库分表分垂直分和水平分,垂直分就是将表按照类似于微服务的思想划分为userLog,orderLog之类的 水品分就是 比方说user表 按照id取模 奇数在一个表中 偶数在一个表(这样的画 以前单表数据量大 划分到多个表后数据量减少,提高查询效率)


在这里插入图片描述

使用shardingjdbc 和shardproxy都可以帮助我们做分库分表 ,为什么会独立2个产品,者2个产品又有什么不同?

在这里插入图片描述

这个是sharding-jdbc的结构图 
sharding-jdbc 作为一个jar 放在java的app中 目前只支持java
我们的业务代码 ----->sharding-jdbc的api就可以把我们的请求进行分库分表,原来访问一个库现在可以通过sharding-jdbc来帮助我们访问多个库,也可以访问多个库中的多个表
  

在这里插入图片描述

shardingProxy 相当于数据库的代理 他脱离了Java的应用,单独部署了一个服务。我们的应用就像访问mysql一样访问 shardingProxy就可以,sharding-proxy 帮我们完成分库分表的逻辑
这里有一个register-center(注册中心)的概念,我们通常说的注册中心就会想到微服务中的eureka,nacos,zk这些,这里是shardingsphere想打造一个自己的注册中心 将所有服务都放在他的注册中心上集中管理,吧分库分表 像类似于微服务一样集中管理    我的应用就不需要管分库分表的配置

呢么Sharding-jdbc和Sharding-proxy有什么优缺点,分别应用于什么样子的场景?

sharding-jdbc 是一个jar嵌到java代码中的,侵入性高,但是他灵活性高,我可以想怎么配置分库分表规则 就怎么配置,类似于一个jdbc的加强版
jdbc可以连接什么数据库,我sharding-jdbc就可以连什么数据库

sharding-proxy 独立部署的服务,让sharding-proxy 和下面的数据库打交道,都得提前定义好分库分表得规则,这样做就不能达到灵活配置,
sharding-proxy不能对接所有数据库,目前只支持mysql,postGresql,其他产品不支持
接下来我们看一下sharding-jdbc,sharding-jdbc的核心功能就是数据分片以及读写分离(mysql做),读写分离就是我们搭建一个mysql的 master,slave的主从集群,有一个master,slave,slave会同步master的数据,这个时候我们的app就会吧所有对数据库写的操作放在master上,所有对数据库读的操作放在slave上,	 

在这里插入图片描述

就类似于上述的图一样,读写分离的好处就是以前一个数据库承担的访问压力现在分担到2个数据库了,你读的请求放在从库,甚至你的从库还可以具备扩展的能力
可以搭建更多的从库来提升你集群的性能


呢么 数据分片该怎么做  首先shardingSphere有这几个核心概念

在这里插入图片描述

大致就是这样子的

在这里插入图片描述

shardingSphere 实战
shardingsphere是用来做分库分表的
我们此时用mybatisplus+jdbc+shardingSphere来测试下

在这里插入图片描述

# 1.pom 父parent 
   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>MyShardingSphere</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
    # sharding jdbc的pom包
    <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</artifactId>
        </dependency>
        # springboot的test包
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
                # 数据库连接druid druid连接池
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
#   mpplus 
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>
2.实体类以及mapper

在这里插入图片描述

#  t_user实体类
@TableName("t_user")
public class User {

    private Long userId;
    private String username;
    private String ustatus;
    private int uage;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUstatus() {
        return ustatus;
    }

    public void setUstatus(String ustatus) {
        this.ustatus = ustatus;
    }

    public int getUage() {
        return uage;
    }

    public void setUage(int uage) {
        this.uage = uage;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", username='" + username + '\'' +
                ", ustatus='" + ustatus + '\'' +
                ", uage=" + uage +
                '}';
    }
}

3. mapper

在这里插入图片描述

4.yaml配置文件  这里用分库分表的配置

在这里插入图片描述

5. 我们注入mapper

@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingJDBCTest {
    @Resource
    UserMapper userMapper;

    @Test
    public void adduser() {
        for (int i = 0; i < 10; i++) {
            User c = new User();
            c.setUserId(Long.valueOf(i));
            c.setUage(1000+i);
            c.setUsername("zhangsan.." + i);
            c.setUstatus("0");
            userMapper.insert(c);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

插入进来了 这就代表我们的配置起作用了,我们定义了一个m1数据库

----------------------------------------------------------------->>>>>>>>>>>>>>>>>
我们现在只是定义一个数据源,并且吧数据插入到一个表中了,如果现在插入10条数据,将数据分片到2个user表中,将数据均匀分布在2个表中 该怎么去做

我这里有2个表 t_user_1和t_user_2

在这里插入图片描述

首先看user对象

在这里插入图片描述

新增加 数据  取消 userId我们此时采用雪花算法 实现id的自动生成
    @Test
    public void adduser() {
        for (int i = 0; i < 10; i++) {
            User c = new User();
          //  c.setUserId(Long.valueOf(i));
            c.setUage(1000+i);
            c.setUsername("zhangsan.." + i);
            c.setUstatus("0");
            userMapper.insert(c);
        }
    }
#配置数据源  定义一个m1 数据源
spring.shardingsphere.datasource.names=m1
#  m1 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/user?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

#配置真实表分布                      数据的真实分布在 在         {   m1.t_user_1  和 m1.t_user_2}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=m1.t_user_$->{1..2}

#(mysql)主键生成策略  数据库的Id 拆分策略  数据库 生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=user_id {mysql 数据库主键生成策略}
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE{雪花算法}
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1
#配置分表策略  inline 模式  分片键  基于请求进行分
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=user_id{基于user_id来拆分}
#分片算法  按照分片键取模加1 计算在那个表中  {按照取模来拆分}
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=t_user_$->{user_id%2+1}
# 展示sql
spring.shardingsphere.props.sql.show = true

在这里插入图片描述
在这里插入图片描述

db

在这里插入图片描述
在这里插入图片描述

看这样的配置就把我们的insert 插入到不同的表中了(取模均匀) 这样当我们进行查询的时候  原本一个表的数据分担到两个表中 之后 数据量降低 自然我们的查询效率就高
shardingphere 会根据我们进行分库分表
m1 代表数据库,对user_id进行一个主键生成,通过雪花算法 
根据user_id 的奇偶性来拆分
	
现在我只是分了1个库中的2个表 ,如果我现在要分到2个库中该怎么处理

在这里插入图片描述

就类似于这样  我们的yaml怎么配置呢

在这里插入图片描述

#配置数据源  定义一个m1和m2数据源

spring.shardingsphere.datasource.names=m1,m2
#  m1 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/user?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456


#  m2 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://127.0.0.1:3306/user_1 ?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456

#配置真实表分布         数据的真实分布在 在 先定义那个库 再定义哪一个表{   m1.t_user_1  和 m1.t_user_2}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=m$->{1..2}.t_user_$->{1..2}

#主键生成策略  数据库的Id 拆分策略  数据库 生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1
#配置分表策略  inline 模式  分片键  基于请求进行分
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=user_id
#分片算法  按照分片键取模加1 计算在那个表中
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=t_user_$->{user_id%2+1}
#分库算法  和上面的分表算法一致

spring.shardingsphere.sharding.tables.user.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=m$->{user_id%2+1}

spring.shardingsphere.props.sql.show = true


 因为我们的分库分表算法配置的是如果user_id 为奇数 就会落
 入到 m2.t_user2 ,如果user_id为偶数 就会落入到中m1.t_user1 
我们吧之前的数据删除了直接跑一边效果 就可以看到 
#我们可以指定我们的分片算法以及分库算法来实现我们的请求具体落在拿哪一个库中或者哪一个表中
现在我吧数据insert到2个库存中了 我能不能查询出来呢
# 

    @Test
    public void queryUser(){
        //select * from user
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.orderByDesc("userId");
//        wrapper.eq("userId",553684818806706177L);
//        wrapper.in()
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(course -> System.out.println(course));
    }

在这里插入图片描述
在这里插入图片描述

看上面逻辑sql : Logic SQL: SELECT  user_id,username,ustatus,uage  FROM user
# 实际sql
2022-06-27 08:10:45.854  INFO 17308 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1
2022-06-27 08:10:45.854  INFO 17308 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2
2022-06-27 08:10:45.854  INFO 17308 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1
2022-06-27 08:10:45.854  INFO 17308 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2
就可以证明他查询了2个库的4个表
#  当我们使用
 //select * from user  where user_id='748089358543753216L'  或者in的话
  @Test
    public void queryCourse(){
        //select * from user  where user_id='748089358543753216L'
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.orderByDesc("userId");
      wrapper.eq("user_id",748089358543753216L);
//        wrapper.in()
        System.out.println("--------------------------------");
        System.out.println("--------------------------------");
        System.out.println("--------------------------------");
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(course -> System.out.println(course));
    }
}

在这里插入图片描述
在这里插入图片描述

可以看到我们的目标sql 以及实际sql直接去m1表的t_user_1 来查询了 因为它会首先根据你分库分表的规则计算你的user_id 从那个库中的那个表中获取


他已经按照你分库分表的规则找到这一条数据 也就是说他查询的效率很高,分库分表的意义 我如果不用分库分表user表的数据太多是不是就会影响我查询效率,我现在分库分表之后 比如说我现在把它分成了2个表,如果我的user表有1000W条数据,吧他分成2个表 每个表只有500w 条数据,500 w条数据, 我按照id 来查询 他扫描的数据就少了 这就是分库分表的意义
#  当我们使用between and 的时候此时的这种规则就不适合我们查询了
    @Test
    public void queryCourseRange(){
        //select * from user  where user_id between  553684818806706177L and  553684819184193537L
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("user_id",553684818806706177L,553684819184193537L);
         List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(user -> System.out.println(user));
    }
}

报错异常当前的策略不支持我们的查询 

在这里插入图片描述

INLINE精确分表 对user_Id已知的情况 比如说user_Id  等于 . user_Id in 做一个精确的分片.
因为between and () 中间很多数据  使用inline这种只能匹配 等于 或者in 类型
#  这时候我们要使用第二种策略了  standard
#配置数据源  定义一个m1和m2数据源
spring.shardingsphere.datasource.names=m1,m2
#  m1 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/user?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456
#  m2 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://127.0.0.1:3306/user_1 ?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456
#配置真实表分布         数据的真实分布在 在 先定义那个库 再定义哪一个表{   m1.t_user_1  和 m1.t_user_2}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=m$->{1..2}.t_user_$->{1..2}
#主键生成策略  数据库的Id 拆分策略  数据库 生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1
# 基于standard  这种模式进行分片  表分片键
spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=user_id
# 精确匹配
spring.shardingsphere.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.lvhao.standard.MyPreciseTableShardingAlgorithm
# between  and 范围匹配
spring.shardingsphere.sharding.tables.user.table-strategy.standard.range-algorithm-class-name=com.lvhao.standard.MyRangeTableShardingAlgorithm
# 基于standard  这种模式进行分片  库分片键
spring.shardingsphere.sharding.tables.user.database-strategy.standard.sharding-column=user_id
# 精确匹配
spring.shardingsphere.sharding.tables.user.database-strategy.standard.precise-algorithm-class-name=com.lvhao.standard.MyPreciseDSShardingAlgorithm
# between  and 范围匹配
spring.shardingsphere.sharding.tables.user.database-strategy.standard.range-algorithm-class-name=com.lvhao.standard.MyRangeDSShardingAlgorithm
spring.shardingsphere.props.sql.show=true

在这里插入图片描述


//精确分库 策略  
public class MyPreciseDSShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    //select * from user where user_Id = ? or cid in (?,?)
    // 根据具体的value 找具体的库存
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        String cid = shardingValue.getColumnName();
        Long userIdvalue = shardingValue.getValue();
        //实现 user_Id$->{cid%2+1)
        BigInteger shardingValueB = BigInteger.valueOf(userIdvalue);
        BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1"));
        String key = "m"+resB;
        System.out.println(userIdvalue+".使用.."+key+"..库");
        if(availableTargetNames.contains(key)){
            return key;
        }
        //
        throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config");
    }
}

/*
*
* standard 的精确匹配  表 
* */

public class MyPreciseTableShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    //select * from user where user_Id = ? or cid in (?,?)
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        // 目标表
        String logicTableName = shardingValue.getLogicTableName();
        //user_Id
        String user_Id = shardingValue.getColumnName();
         根据具体的值实现 取模算法  找到对应的表
        //具体的值
        Long userIdvalue = shardingValue.getValue();
        //实现 user_id_$->{user_Id%2+1)
        BigInteger userIdvalueB = BigInteger.valueOf(userIdvalue);
        BigInteger resB = (userIdvalueB.mod(new BigInteger("2"))).add(new BigInteger("1"));
        String key = "t_"+logicTableName+"_"+resB;
        /
        System.out.println(userIdvalue+".使用.."+key+"..表");
        if(availableTargetNames.contains(key)){
            return key;
        }
       
        throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config");
    }
}

#  分库策略  between and 
public class MyRangeDSShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        //select * from user where user_id between 1 and 100;
        Long upperVal = shardingValue.getValueRange().upperEndpoint();//100
        Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1

        String logicTableName = shardingValue.getLogicTableName();
        ///  2个库都用
        return Arrays.asList("m1","m2");
    }
}

#  分表策略  between and 
public class MyRangeTableShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        //select * from user where user_id between 1 and 100;
        Long upperVal = shardingValue.getValueRange().upperEndpoint();//100
        Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1
        String logicTableName = "t_"+shardingValue.getLogicTableName();
        ///  2个表都用
        return Arrays.asList(logicTableName+"_1",logicTableName+"_2");
    }
}

在这里插入图片描述
在这里插入图片描述

 看日志  就能看出来
(逻辑表) Logic SQL: SELECT  user_id,username,ustatus,uage  FROM user  
 WHERE  user_id BETWEEN ? AND ?
(实际表) Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1  
 WHERE  user_id BETWEEN ? AND ? ::: [553684818806706177, 553684819184193537]
2022-06-28 00:11:06.213  INFO 9668 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2  
 WHERE  user_id BETWEEN ? AND ? ::: [553684818806706177, 553684819184193537]
2022-06-28 00:11:06.213  INFO 9668 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1  
 WHERE  user_id BETWEEN ? AND ? ::: [553684818806706177, 553684819184193537]
2022-06-28 00:11:06.213  INFO 9668 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2  
 WHERE  user_id BETWEEN ? AND ? ::: [553684818806706177, 553684819184193537]
shandred策略 支持   Precise查询和Range查询,我现在是按照userId 进行分片策略  我现在加了一个uage字段,看我user表结构

在这里插入图片描述

你看 现在 我不仅仅要对user_Id进行between and 查询 也要对uage进行查询,我们的uage也是按照就划分的,如果使用shandred 的话 的要查询4次数据库,现在我如何做到查询一次数据库呢  因为uage也是按照奇偶划分的
  @Test
    public void queryCourseComplex(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("user_id",553684818806706177L,553684819184193537L);
        wrapper.eq("uage",1008);

        List<User> courses = userMapper.selectList(wrapper);
        courses.forEach(course -> System.out.println(course));
    }

在这里插入图片描述

看sql 我们查询了4个表 因为现在userId也是根据奇偶数划分的 我们如何只查询一次表
 Logic SQL: SELECT  user_id,username,ustatus,uage  FROM user  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ?


Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ? ::: [553684818806706177, 553684819184193537, 1009, 1009]
2022-06-28 07:46:18.963  INFO 7952 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ? ::: [553684818806706177, 553684819184193537, 1009, 1009]
2022-06-28 07:46:18.963  INFO 7952 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_1  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ? ::: [553684818806706177, 553684819184193537, 1009, 1009]
2022-06-28 07:46:18.963  INFO 7952 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ? ::: [553684818806706177, 553684819184193537, 1009, 1009]
 
#  基于complex 的分片策略  对多字段进行分库分表
#配置数据源  定义一个m1和m2数据源
spring.shardingsphere.datasource.names=m1,m2
#  m1 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/user?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456
#  m2 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://127.0.0.1:3306/user_1 ?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456
#配置真实表分布         数据的真实分布在 在 先定义那个库 再定义哪一个表{   m1.t_user_1  和 m1.t_user_2}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=m$->{1..2}.t_user_$->{1..2}
#主键生成策略  数据库的Id 拆分策略  数据库 生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1
#complex复杂分片策略
spring.shardingsphere.sharding.tables.user.table-strategy.complex.sharding-columns= user_id, uage
spring.shardingsphere.sharding.tables.user.table-strategy.complex.algorithm-class-name=com.lvhao.complex.MyComplexTableShardingAlgorithm
#分库策略
spring.shardingsphere.sharding.tables.user.database-strategy.complex.sharding-columns=user_id, uage
spring.shardingsphere.sharding.tables.user.database-strategy.complex.algorithm-class-name=com.lvhao.complex.MyComplexDSShardingAlgorithm
spring.shardingsphere.props.sql.show=true





在这里插入图片描述

基于complex的分库策略
public class MyComplexDSShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
//    SELECT *  FROM t_user
//    WHERE  user_id BETWEEN ? AND ? AND uage = ?
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
       // 获取对应参数
        Range<Long> cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("user_id");
       // uage
        Collection<Long> userAgeValue = shardingValue.getColumnNameAndShardingValuesMap().get("uage");
        // user_id 的上下线
        Long upperVal = cidRange.upperEndpoint();
        Long lowerVal = cidRange.lowerEndpoint();

        List<String> res = new ArrayList<>();

        for(Long userAge: userAgeValue){

            BigInteger userAgeB = BigInteger.valueOf(userAge);
            BigInteger target = (userAgeB.mod(new BigInteger("2"))).add(new BigInteger("1"));
		// 获取哪一个表 根据userAge 取模
            res.add("m"+target);
        }

        return res;
    }
}

基于complex的分表策略
public class MyComplexTableShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
        // 获取对应参数
        Range<Long> cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("user_id");
        // uage
        Collection<Long> userAgeValue = shardingValue.getColumnNameAndShardingValuesMap().get("uage");

        Long upperVal = cidRange.upperEndpoint();
        Long lowerVal = cidRange.lowerEndpoint();

        List<String> res = new ArrayList<>();

        for(Long uage: userAgeValue){

            BigInteger uageB = BigInteger.valueOf(uage);
            BigInteger target = (uageB.mod(new BigInteger("2"))).add(new BigInteger("1"));
		// 获取哪一个表 根据userAge 取模  获取那一个库
            res.add("t_"+shardingValue.getLogicTableName()+"_"+target);
        }

        return res;
    }
}

在这里插入图片描述

这样的话 我们的实际sql就是一条  ,之前查询age 查 询了4次 我现在只需要查询1次,通过这样的查询,可以提高我们sql的查询效率
Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2  
 WHERE  user_id BETWEEN ? AND ? AND uage = ? AND uage = ? ::: [553684818806706177, 553684819184193537, 1009, 1009]
最后一种策略就是强制路由 (和路由键没有关系)
#配置数据源  定义一个m1和m2数据源
spring.shardingsphere.datasource.names=m1,m2
#  m1 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://127.0.0.1:3306/user?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456
#  m2 数据库的连接配置 m1的数据源名称  type driver user
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://127.0.0.1:3306/user_1 ?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456
#配置真实表分布         数据的真实分布在 在 先定义那个库 再定义哪一个表{   m1.t_user_1  和 m1.t_user_2}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=m$->{1..2}.t_user_$->{1..2}
#主键生成策略  数据库的Id 拆分策略  数据库 生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=user_id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1
# 基于hint 强制路由
spring.shardingsphere.sharding.tables.user.table-strategy.hint.algorithm-class-name=com.lvhao.hint.MyHintTableShardingAlgorithm
spring.shardingsphere.props.sql.show=true



..路由键路由规则
public class MyHintTableShardingAlgorithm implements HintShardingAlgorithm<Integer> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
        String key = "t_" + shardingValue.getLogicTableName() + "_" + shardingValue.getValues().toArray()[0];
        if (availableTargetNames.contains(key)) {
            System.out.println("---------key" + key);
            return Arrays.asList(key);
        }
        throw new UnsupportedOperationException("route " + key + " is not supported ,please check your config");
    }
}
    @Test
    public void queryCourseByHint(){
        HintManager hintManager = HintManager.getInstance();
        // 定义表  
        hintManager.addTableShardingValue("user",2);
        List<User> courses = userMapper.selectList(null);
        courses.forEach(course -> System.out.println(course));
        hintManager.close();
    }

在这里插入图片描述

#  这样日志就可以看到了  我们此时只是查询t_user_2的表
2022-06-28 08:17:05.099  INFO 9648 --- [           main] ShardingSphere-SQL                       : Actual SQL: m1 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2
2022-06-28 08:17:05.099  INFO 9648 --- [           main] ShardingSphere-SQL                       : Actual SQL: m2 ::: SELECT  user_id,username,ustatus,uage  FROM t_user_2

还可以配置广播表,广播表中就是每个库中都会保留全量的数据,比如说字典表(性别 男女 或者状态  什么的)
Logic SQL: INSERT INTO t_dict  ( ustatus,uvalue )  VALUES  ( ?,? )
#  看这样就有我们的全量的数据
Actual SQL: m1 ::: INSERT INTO t_dict  ( ustatus,
uvalue , dict_id)  VALUES  (?, ?, ?) ::: [1, 正常, 749758279579598848]
2022-07-01 22:31:43.720  INFO 21300 --- [           main] ShardingSphere-SQL                       Actual SQL: m2 ::: INSERT INTO t_dict  ( ustatus,
uvalue , dict_id)  VALUES  (?, ?, ?) ::: [1, 正常, 749758279579598848]

在这里插入图片描述

shardingjdbc的sql限制 shardingJDBC 不支持一些sql

在这里插入图片描述

mysql 主从的效果 就是在主库的写操作会同步到从库上,主从同步做的就是吧所有的读的操作放在从库上,吧所有写的操作放在主库上  我们现在要配置读写分离 一个读库 一个写库
需要吧主从规则交给sharding-jdbc  他来帮我们做读写分离
#读写分离
spring.shardingsphere.datasource.names=m0,s0

spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3307/masterdemo?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=root

spring.shardingsphere.datasource.s0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.s0.url=jdbc:mysql://localhost:3308/masterdemo?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.s0.username=root
spring.shardingsphere.datasource.s0.password=root
#读写分离规则, m0 主库,s0 从库  主库  ds0(规则名字)
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0
从库
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names[0]=s0
#基于读写分离的表分片  拆分那个表
spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=ds0.t_dict
#  分片算法
spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id
spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1

spring.shardingsphere.props.sql.show = true
spring.main.allow-bean-definition-overriding=true


分库分表带来的问题,一旦你使用了分库分表,你的sql 就不能像以前呢样写的随心所欲了,你的sql会收到很多限制 因为在shardingjdbc中 有的sql不支持

我们使用分库分表的核心问题 就是单机容量的问题, 是不是可以不分  我们可以优先考虑缓存或者ES这些技术,如果缓存过后我们的数据量还是很大,且数据业务增长很快(我i们的考虑数据的业务增长)最后才考虑分库分表,
我们应该分析数据增长量  对持续增长的业务数据优先考虑分库分表,业务预估多少年 阿里建议预估三年
shardingproxy 


shardingproxy 和shardingjdbc 功能都是一样的 都是做分库分表的,呢么和shardingjdbc有什么去区别

sharingjdbc 是一个应用程序的扩展包,分库分表代码写在业务程序中,他来帮我们做分库分表

shardingproxy 是一个服务.独立部署成一个服务, 但是proxy 本身不存数据库 通过分库分表逻辑 将你的数据存储在实际的表中,应用人员只需要连接mysql一样就可以使用了

在这里插入图片描述


 
shardingjdbc 是给开发人员用的。开发人员可以在应用程序当中写自己的代码  简化分库分表逻辑  可以定制化自己的分库分表策略。
shardingproxy 是给运维人员用的。让应用不需要感知分库分表的存在, 应用只需要像连接Mysql一样连接就可以了,当mysql如果存储不下,运维这边可以部署一个shardingproxy服务,吧数据在shardingproxy背后进行分库分表就可以了,目前shardingproxy 只支持 postgreSql和mysql 


shardingProxy 是一个服务他的核心思想就是让应用无感知 ,你应用不需要知道我后面分库分表怎么分的。查询自动会查询真实表,比shardingjdbc方便多了。对应用无感知,就像用单机数据库一样呢么用
如果只是简单的sql 只做 一些insert update  shardingproxy就够用了。因为对你应用 无感知

同时sherdingProxy 也支持吧自己的节点配置到zk上,做高可用的时候 就像kafka一样 多个节点连接同一个zk上就可以

在这里插入图片描述
在这里插入图片描述

就像这样一样  对于主键生成规则  可以用uuid 也可以用雪花算法,也可以用redis的自增加1 ,y也可以通过spi机制 自定义


https://blog.csdn.net/qq_43631716/article/details/120400972  具体可以看看这个大佬的博客

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值