SpringBoot2.0.4+Jpa+ShardingSphere3.0.0.M2进行数据库分表

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。

分表执行的5个步骤:

1.Sql解析

分表的表达式:order_${0..1}

分为两个表:order_0,order_1

2.Sql路由

就是根据分表策略,找到具体要curd的表

根据解析上下文匹配数据库和表的分片策略,并生成路由路径。 对于携带分片键的SQL,根据分片键的不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN)。 不携带分片键的SQL则采用广播路由。

3.Sql改写

将逻辑SQL改写为可以在真实数据库中正确执行的SQL。 它包括正确性改写和优化改写两部分。

4.Sql执行

ShardingSphere采用一套自动化的执行引擎,负责将路由和改写完成之后的真实SQL安全且高效发送到底层数据源执行。 它不是简单地将SQL通过JDBC直接发送至数据源执行;也并非直接将执行请求放入线程池去并发执行。它更关注平衡数据源连接创建以及内存占用所产生的消耗,以及最大限度地合理利用并发等问题。 执行引擎的目标是自动化的平衡资源控制与执行效率。

5.Sql归并

将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。

ShardingSphere支持的结果归并从功能上分为遍历、排序、分组、分页和聚合5种类型,它们是组合而非互斥的关系。 从结构划分,可分为流式归并、内存归并和装饰者归并。流式归并和内存归并是互斥的,装饰者归并可以在流式归并和内存归并之上做进一步的处理。

中文手册:shardingsphere中文手册

我们在项目中怎么用:

1.maven配置


      io.shardingsphere
      sharding-jdbc-spring-boot-starter
      3.0.0.M2


      com.alibaba
      druid
      1.1.9

2.properties配置

#分表,数据源由sharding配置,管理所有的表(包括不分片的表)
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=false
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
#分表所在的数据库
sharding.jdbc.datasource.names=dbName 
sharding.jdbc.datasource.dbName.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.dbName.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.dbName.url=jdbc:mysql://xxx:3306/dbName?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
sharding.jdbc.datasource.dbName.username=xx
sharding.jdbc.datasource.dbName.password=xx
#为tableNameA分表,需要事先在数据库建立对应的表,这里为:tableNameA_1,tableNameA_2,....,tableNameA_49,以及tableNameA 
sharding.jdbc.config.sharding.tables.tableNameA.actual-data-nodes=dbName.tableNameA_$->{1..49},dbName.tableNameA 
 #分表字段
sharding.jdbc.config.sharding.tables.tableNameA.table-strategy.standard.sharding-column=id
#实现分表算法的类的名字
sharding.jdbc.config.sharding.tables.tableNameA.table-strategy.standard.precise-algorithm-class-name=com.device.bind.config.ShardingTableConfig 


#为tableNameB分10张表,tableNameB_0...tableNameB_9这10张表
sharding.jdbc.config.sharding.tables.tableNameB.actual-data-nodes=dbName.tableNameB_$->{0..9} 
sharding.jdbc.config.sharding.tables.tableNameB.table-strategy.standard.sharding-column=id 
sharding.jdbc.config.sharding.tables.tableNameB.table-strategy.standard.precise-algorithm-class-name=com.device.bind.config.ShardingTableConfig

#Druid连接池配置
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.max-wait=60000
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.validation-query-timeout=30000
#是否在获得连接后检测其可用性
spring.datasource.druid.test-on-borrow=false
#是否在连接放回连接池后检测其可用性
spring.datasource.druid.test-on-return=false

这里对tableNameA及tableNameB两张表进行分表,一个分了50张表,一个分了10张表,这些表都需要自己在数据库中建立。

分表的字段均为id,分表的算法写在ShardingTableConfig类中,该类实现了PreciseShardingAlgorithm>接口,该接口又继承了ShardingAlgorithm类。从接口名字上我们可以看出,我们要实现的是精确分表算法。

注意:不分片的表(不进行分表的表)也会被ShardingSphere管理,可以通过配置两个数据源来讲分片的表与不分片的表分隔开。ShardingSphere3.0目前不支持distant查询,3.1支持。

3.实现自己的精确分表算法

/**
 * 数据库分表
 */
public class ShardingTableConfig implements PreciseShardingAlgorithm {
    //tableNameA表的分表条件,当id大于该值时,向tableNameA_1...tableNameA_49插入或查询数据
    private static long tableNameATableThreshold = 85000;
    //tableNameA表 分为50张表
    private static int tableNameASplitTableSize = 50;
    //tableNameB表 分为10张表
    private static int tableNameBSplitTableSize = 10;

    /**
     * 精确分片算法 用于=和IN
     * @param availableTargetNames
     * @param shardingValue
     * @return
     */
    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
        System.out.println(availableTargetNames);
        String tableNameA = "tableNameA";
        if (availableTargetNames.contains(tableNameA)) {  
            if (shardingValue.getColumnName().equalsIgnoreCase("id")) {
                int suffix = -1;
                Long id = (Long) shardingValue.getValue();
                if (id < tableNameATableThreshold ) {
                    return tableNameA;
                } else {
                    suffix = (int) (id % tableNameASplitTableSize );
                    String s = (tableNameA + "_" + suffix).toLowerCase();
                    return s;
                }
            }
            throw new IllegalArgumentException("分表字段:member_id缺失");
        }

        String tableNameB = "tableNameB ";
        if (availableTargetNames.contains(tableNameB )) {
            if (shardingValue.getColumnName().equalsIgnoreCase("id")) {
                int suffix = -1;
                Long id = (Long) shardingValue.getValue();
                suffix = (int) (id % tableNameBSplitTableSize );
                String s = ("tableNameB " + "_" + suffix).toLowerCase();
                return s;
            }
            throw new IllegalArgumentException("分表字段:member_id缺失");
        }
        return null;
    }
}

 

你可能感兴趣的:(mysql,spring,boot,分表)