ShardingSphere(3)—分片算法篇

举报
小白弟弟 发表于 2022/01/05 00:48:04 2022/01/05
【摘要】 2.3.3、分片算法日常:使用的inline分片算法即提供一个分片键和一个分片表达式来制定分片算法。这种方式配置简单,功能灵活,是分库分表最佳的配置方式,并且对于绝大多数的分库分片场景来说,都已经非常好用了。针对一些更为复杂的分片策略,例如多分片键、按范围分片等场景,inline分片算法就有点力不从心了所以ShardingSphere目前提供了一共五种分片策略:NoneShardingSt...

2.3.3、分片算法

  • 日常:使用的inline分片算法即提供一个分片键和一个分片表达式来制定分片算法。这种方式配置简单,功能灵活,是分库分表最佳的配置方式,并且对于绝大多数的分库分片场景来说,都已经非常好用了。

  • 针对一些更为复杂的分片策略,例如多分片键、按范围分片等场景,inline分片算法就有点力不从心了

  • 所以ShardingSphere目前提供了一共五种分片策略:

    • NoneShardingStrategy

      • 不分片。这种严格来说不算是一种分片策略了。只是ShardingSphere也提供了这么一个配置。
    • InlineShardingStrategy

      • 最常用的分片方式

      • 配置参数: inline.shardingColumn 分片键;inline.algorithmExpression分片表达式

      • 实现方式: 按照分片表达式来进行分片。

    • StandardShardingStrategy(解决区间查询)

      • 只支持单分片键的标准分片策略。

      • 配置参数:standard.sharding-column 分片键;standard.precise

      • algorithm-class-name 精确分片算法类名;standard.range-algorithm

      • class-name 范围分片算法类名

      • 实现方式:

        • shardingColumn指定分片算法。
        • preciseAlgorithmClassName 指向一个实现了io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm接口的java类名,提供按照 = 或者 IN 逻辑的精确分片
        • rangeAlgorithmClassName 指向一个实现了io.shardingsphere.api.algorithm.sharding.standard.RangeShardingAlgorithm接口的java类名,提供按照Between 条件进行的范围分片。
      • 说明:

        • 其中精确分片算法是必须提供的,而范围分片算法则是可选的。

    代码实现:

    配置:

    #配置数据源
    spring.shardingsphere.datasource.names=m1,m2
    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://localhost:3306/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    spring.shardingsphere.datasource.m1.username=root
    spring.shardingsphere.datasource.m1.password=root
    
    #配置数据源
    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://localhost:3306/coursedb2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    spring.shardingsphere.datasource.m2.username=root
    spring.shardingsphere.datasource.m2.password=root
    
    # 要生成多少张真实表(#配置真实表分布)
    spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
    # 表的主键是什么(主键生成策略)
    spring.shardingsphere.sharding.tables.course.key-generator.column=cid
    spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
    spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1
    
    spring.shardingsphere.sharding.tables.course.table-strategy.standard.sharding-column=cid
    spring.shardingsphere.sharding.tables.course.table-strategy.standard.precise-algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyPreciseTableShardingAlgorithm
    spring.shardingsphere.sharding.tables.course.table-strategy.standard.range-algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyRangeTableShardingAlgorithm
    
    spring.shardingsphere.sharding.tables.course.database-strategy.standard.sharding-column=cid
    spring.shardingsphere.sharding.tables.course.database-strategy.standard.precise-algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyPreciseDSShardingAlgorithm
    spring.shardingsphere.sharding.tables.course.database-strategy.standard.range-algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyRangeDSShardingAlgorithm
    
    #其他运行属性
    spring.shardingsphere.props.sql.show=true
    # 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
    spring.main.allow-bean-definition-overriding=true
    

    分片算法类:

    package com.zhz.shardingspheredemo.algorithm;
    
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
    
    import java.math.BigInteger;
    import java.util.Collection;
    
    
    /**
     * @Description: 精确的数据库分配算法
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    
    public class MyPreciseDSShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
        //select * from course where cid = ? or cid in (?,?)
        @Override
        public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
            String logicTableName = shardingValue.getLogicTableName();
            String cid = shardingValue.getColumnName();
            Long cidValue = shardingValue.getValue();
            //实现 course_$->{cid%2+1)
            BigInteger shardingValueB = BigInteger.valueOf(cidValue);
            BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1"));
            String key = "m"+resB;
            if(availableTargetNames.contains(key)){
                return key;
            }
            //couse_1, course_2
            throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config");
        }
    }
    
    package com.zhz.shardingspheredemo.algorithm;
    
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
    
    import java.math.BigInteger;
    import java.util.Collection;
    
    
    /**
     * @Description: 精确的表分配算法
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    public class MyPreciseTableShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
        //select * from course where cid = ? or cid in (?,?)
        @Override
        public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
            String logicTableName = shardingValue.getLogicTableName();
            String cid = shardingValue.getColumnName();
            Long cidValue = shardingValue.getValue();
            //实现 course_$->{cid%2+1)
            BigInteger shardingValueB = BigInteger.valueOf(cidValue);
            BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1"));
            String key = logicTableName+"_"+resB;
            if(availableTargetNames.contains(key)){
                return key;
            }
            //couse_1, course_2
            throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config");
        }
    }
    
    package com.zhz.shardingspheredemo.algorithm;
    
    import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
    import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
    
    import java.util.Arrays;
    import java.util.Collection;
    
    
    /**
     * @Description: 区间分配的分配算法(数据库)
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    public class MyRangeDSShardingAlgorithm implements RangeShardingAlgorithm<Long> {
        @Override
        public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
            //select * from course where cid between 1 and 100;
            Long upperVal = shardingValue.getValueRange().upperEndpoint();//100
            Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1
    
            String logicTableName = shardingValue.getLogicTableName();
            return Arrays.asList("m1","m2");
        }
    }
    
    package com.zhz.shardingspheredemo.algorithm;
    
    import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
    import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
    import sun.rmi.runtime.Log;
    
    import java.util.Arrays;
    import java.util.Collection;
    
    
    /**
     * @Description: 区间分配的分片算法(表)
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    public class MyRangeTableShardingAlgorithm implements RangeShardingAlgorithm<Long> {
        @Override
        public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
            //select * from course where cid between 1 and 100;
            Long upperVal = shardingValue.getValueRange().upperEndpoint();//100
            Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1
    
            String logicTableName = shardingValue.getLogicTableName();
            return Arrays.asList(logicTableName+"_1",logicTableName+"_2");
        }
    }
    

    测试类

      @Test
        public void queryOrderRange(){
            //select * from course
            QueryWrapper<Course> wrapper = new QueryWrapper<>();
            wrapper.between("cid",1434444618337914881L,1434444620539924482L);
    //        wrapper.in()
            List<Course> courses = courseMapper.selectList(wrapper);
            courses.forEach(course -> System.out.println(course));
        }
    

    image-20210905212259703

    • ComplexShardingStrategy(多字段查询)

      • 支持多分片键的复杂分片策略。

      • 配置参数:complex.sharding-columns 分片键(多个);complex.algorithm-class-name 分片算法实现类。

      • 实现方式:

        • shardingColumn指定多个分片列。
        • algorithmClassName指向一个实现了org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm接口的java类名。提供按照多个分片列进行综合分片的算法。

    配置类

    #配置数据源
    spring.shardingsphere.datasource.names=m1,m2
    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://localhost:3306/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    spring.shardingsphere.datasource.m1.username=root
    spring.shardingsphere.datasource.m1.password=root
    
    #配置数据源
    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://localhost:3306/coursedb2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    spring.shardingsphere.datasource.m2.username=root
    spring.shardingsphere.datasource.m2.password=root
    
    # 要生成多少张真实表(#配置真实表分布)
    spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
    # 表的主键是什么(主键生成策略)
    spring.shardingsphere.sharding.tables.course.key-generator.column=cid
    spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
    spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1
    
    # 第三种
    spring.shardingsphere.sharding.tables.course.table-strategy.complex.sharding-columns= cid, user_id
    spring.shardingsphere.sharding.tables.course.table-strategy.complex.algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyComplexTableShardingAlgorithm
    
    spring.shardingsphere.sharding.tables.course.database-strategy.complex.sharding-columns=cid, user_id
    spring.shardingsphere.sharding.tables.course.database-strategy.complex.algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyComplexDSShardingAlgorithm
    
    #其他运行属性
    spring.shardingsphere.props.sql.show=true
    # 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
    spring.main.allow-bean-definition-overriding=true
    

    算法类

    package com.zhz.shardingspheredemo.algorithm;
    
    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;
    import java.util.Map;
    
    /**
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    public class MyComplexDSShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
    //    SELECT  cid,cname,user_id,cstatus  FROM course
    //    WHERE  cid BETWEEN ? AND ? AND user_id = ?
        @Override
        public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
            Range<Long> cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("cid");
            Collection<Long> userIdCol = shardingValue.getColumnNameAndShardingValuesMap().get("user_id");
    
            Long upperVal = cidRange.upperEndpoint();
            Long lowerVal = cidRange.lowerEndpoint();
    
            List<String> res = new ArrayList<>();
    
            for(Long userId: userIdCol){
                //course_{userID%2+1}
                BigInteger userIdB = BigInteger.valueOf(userId);
                BigInteger target = (userIdB.mod(new BigInteger("2"))).add(new BigInteger("1"));
    
                res.add("m"+target);
            }
    
            return res;
        }
    }
    
    package com.zhz.shardingspheredemo.algorithm;
    
    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;
    /**
     *
     * @author zhouhengzhe
     * @date 2021/9/4下午3:24
     * @since
     */
    
    public class MyComplexTableShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
        @Override
        public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
            Range<Long> cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("cid");
            Collection<Long> userIdCol = shardingValue.getColumnNameAndShardingValuesMap().get("user_id");
    
            Long upperVal = cidRange.upperEndpoint();
            Long lowerVal = cidRange.lowerEndpoint();
    
            List<String> res = new ArrayList<>();
    
            for(Long userId: userIdCol){
                //course_{userID%2+1}
                BigInteger userIdB = BigInteger.valueOf(userId);
                BigInteger target = (userIdB.mod(new BigInteger("2"))).add(new BigInteger("1"));
    
                res.add(shardingValue.getLogicTableName()+"_"+target);
            }
    
            return res;
        }
    }
    

    测试类

        @Test
        public void queryCourseComplex(){
            QueryWrapper<Course> wrapper = new QueryWrapper<>();
            wrapper.between("cid",1434444618337914881L,1434444620539924482L);
            wrapper.eq("user_id",1009L);
    //        wrapper.in()
            List<Course> courses = courseMapper.selectList(wrapper);
            courses.forEach(course -> System.out.println(course));
        }
    

    image-20210905212547258

    • HintShardingStrategy(定制连表查询)

      • 不需要分片键的强制分片策略。这个分片策略,简单来理解就是说,他的分片键不再跟SQL语句相关联,而是用程序另行指定。对于一些复杂的情况,例如select count(*) from (select userid from t_user where userid in (1,3,5,7,9))这样的SQL语句,就没法通过SQL语句来指定一个分片键。这个时候就可以通过程序,给他另行执行一个分片键,例如在按userid奇偶分片的策略下,可以指定1作为分片键,然后自行指定他的分片策略。

        • 配置参数:hint.algorithm-class-name 分片算法实现类。

        • 实现方式:

          • algorithmClassName指向一个实现了org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm接口的java类名。
        • 在这个算法类中,同样是需要分片键的。而分片键的指定是通过HintManager.addDatabaseShardingValue方法(分库)和HintManager.addTableShardingValue(分表)来指定。

        • 使用时要注意,这个分片键是线程隔离的,只在当前线程有效,所以通常建议使用之后立即关闭,或者用try资源方式打开。

      • 而Hint分片策略并没有完全按照SQL解析树来构建分片策略,是绕开了SQL解析的,所有对某些比较复杂的语句,Hint分片策略性能有可能会比较好。

-- 不支持UNION 
SELECT * FROM t_order1 UNION SELECT * FROM t_order2 INSERT INTO tbl_name (col1, col2,) SELECT col1, col2,FROM tbl_name WHERE col3 = ? 
-- 不支持多层子查询 
SELECT COUNT(*) FROM (SELECT * FROM t_order o WHERE o.id IN (SELECT id FROM t_order WHERE status = ?)) 
-- 不支持函数计算。ShardingSphere只能通过SQL字面提取用于分片的值 
SELECT * FROM t_order WHERE to_date(create_time, 'yyyy-mm-dd') = '2019-01-01';

配置类

#配置数据源
spring.shardingsphere.datasource.names=m1,m2
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://localhost:3306/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root

#配置数据源
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://localhost:3306/coursedb2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=root

# 要生成多少张真实表(#配置真实表分布)
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
# 表的主键是什么(主键生成策略)
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1

# 第四种
spring.shardingsphere.sharding.tables.course.table-strategy.hint.algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyHintTableShardingAlgorithm

#其他运行属性
spring.shardingsphere.props.sql.show=true
# 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
spring.main.allow-bean-definition-overriding=true

算法类

package com.zhz.shardingspheredemo.algorithm;

import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;

import java.util.Arrays;
import java.util.Collection;

/**
 *
 * @author zhouhengzhe
 * @date 2021/9/4下午3:24
 * @since
 */

public class MyHintTableShardingAlgorithm implements HintShardingAlgorithm<Integer> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
        String key = shardingValue.getLogicTableName() + "_" + shardingValue.getValues().toArray()[0];
        if(availableTargetNames.contains(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("course",2);
        List<Course> courses = courseMapper.selectList(null);
        courses.forEach(course -> System.out.println(course));
        hintManager.close();
    }

image-20210905214101602

2.3.4、广播表

course,course2中都有一张表t_dict

CREATE TABLE `t_dict` (
  `dict_id` bigint(20) NOT NULL,
  `ustatus` varchar(100) CHARACTER SET latin1 NOT NULL,
  `uvalue` varchar(100) CHARACTER SET latin1 NOT NULL,
  PRIMARY KEY (`dict_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

配置类

#配置数据源
spring.shardingsphere.datasource.names=m1,m2
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://localhost:3306/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root

#配置数据源
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://localhost:3306/coursedb2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=root

# 要生成多少张真实表(#配置真实表分布)
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
# 表的主键是什么(主键生成策略)
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1

# 第四种
spring.shardingsphere.sharding.tables.course.table-strategy.hint.algorithm-class-name=com.zhz.shardingspheredemo.algorithm.MyHintTableShardingAlgorithm

# 第五种 广播表(数据不变化)
spring.shardingsphere.sharding.broadcast-tables=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.props.sql.show=true
# 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
spring.main.allow-bean-definition-overriding=true

测试类

 @Test
    public void addDict(){
        Dict d1 = new Dict();
        d1.setUstatus("1");
        d1.setUvalue("zc");
        dictMapper.insert(d1);

        Dict d2 = new Dict();
        d2.setUstatus("0");
        d2.setUvalue("bzc");
        dictMapper.insert(d2);
	   dictMapper.insert(user);
    }

image-20210905220607639

2.3.5、绑定表

配置类

spring.shardingsphere.datasource.names=m1
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://localhost:3306/coursedb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root

spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=m1.t_dict_$->{1..2}

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.sharding.tables.t_dict.table-strategy.inline.sharding-column=ustatus
spring.shardingsphere.sharding.tables.t_dict.table-strategy.inline.algorithm-expression=t_dict_$->{ustatus.toInteger()%2+1}

spring.shardingsphere.sharding.tables.user.actual-data-nodes=m1.t_user_$->{1..2}
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
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=ustatus
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=t_user_$->{ustatus.toInteger()%2+1}
#\u7ED1\u5B9A\u8868\u793A\u4F8B
spring.shardingsphere.sharding.binding-tables[0]=user,t_dict

#其他运行属性
spring.shardingsphere.props.sql.show=true
# 通过注册与现有定义同名的定义,设置是否允许覆盖 bean 定义 默认false
spring.main.allow-bean-definition-overriding=true

测试类

 @Test
    public void addDict(){
        Dict d1 = new Dict();
        d1.setUstatus("1");
        d1.setUvalue("zc");
        dictMapper.insert(d1);

        Dict d2 = new Dict();
        d2.setUstatus("0");
        d2.setUvalue("bzc");
        dictMapper.insert(d2);

        for(int i = 0 ; i < 10 ; i ++){
            User user = new User();
            user.setUsername("user No "+i);
            user.setUstatus(""+(i%2));
            user.setUage(i*10);
            userMapper.insert(user);
        }
    }

结果

image-20210905224859403

测试类

 @Test
    public void queryUserStatus(){
        List<User> users = userMapper.queryUserStatus();
        users.forEach(user -> System.out.println(user));
    }

image-20210905224437631

由上面数据知道两个库的表都是奇偶分的!!!

2.4、SQL使用限制

地址:https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/sql/

支持的SQL

image-20210905205654316

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2f7POOr-1631071303450)(https://gitee.com/zhouzhz/images/raw/master/images/image-20210905205707996.png)]

不支持的SQL

image-20210905205727960

image-20210905205740362

DISTINCT支持情况详细说明

支持的SQL

image-20210905205802557

不支持的SQL

image-20210905205822671

2.5、分库分表带来的问题

1、分库分表,其实围绕的都是一个核心问题,就是单机数据库容量的问题。我们要了解,在面对这个问题时,解决方案是很多的,并不止分库分表这一种。但是ShardingSphere的这种分库分表,是希望在软件层面对硬件资源进行管理,从而便于对数据库的横向扩展,这无疑是成本很小的一种方式。

大家想想还有哪些比较好的解决方案?

2、一般情况下,如果单机数据库容量撑不住了,应先从缓存技术着手降低对数据库的访问压力。如果缓存使用过后,数据库访问量还是非常大,可以考虑数据库读写分离策略。如果数据库压力依然非常大,且业务数据持续增长无法估量,最后才考虑分库分表,单表拆分数据应控制在1000万以内。

当然,随着互联网技术的不断发展,处理海量数据的选择也越来越多。在实际进行系统设计时,最好是用MySQL数据库只用来存储关系性较强的热点数据,而对海量数据采取另外的一些分布式存储产品。例如PostGreSQL、VoltDB甚至HBase、Hive、ES等这些大数据组件来存储。

3、从上一部分ShardingJDBC的分片算法中我们可以看到,由于SQL语句的功能实在太多太全面了,所以分库分表后,对SQL语句的支持,其实是步步为艰的,稍不小心,就会造成SQL语句不支持、业务数据混乱等很多很多问题。所以,实际使用时,我们会建议这个分库分表,能不用就尽量不要用。

如果要使用优先在OLTP场景下使用,优先解决大量数据下的查询速度问题。而在OLAP场景中,通常涉及到非常多复杂的SQL,分库分表的限制就会更加明显。当然,这也是ShardingSphere以后改进的一个方向。

4、如果确定要使用分库分表,就应该在系统设计之初开始对业务数据的耦合程度和使用情况进行考量,尽量控制业务SQL语句的使用范围,将数据库往简单的增删改查的数据存储层方向进行弱化。并首先详细规划垂直拆分的策略,使数据层架构清晰明了。而至于水平拆分,会给后期带来非常非常多的数据问题,所以应该谨慎、谨慎再谨慎。一般也就在日志表、操作记录表等很少的一些边缘场景才偶尔用用。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。