分库分表实战及中间件(二)

分库分表实战及中间件(二)

前言

分库分表实战及中间件(一)中我们使用了在代码中使用硬编码的方式手动定义路由规则以及获取不同表进行分表设计。

此篇使用中间件来进行分表操作,这儿使用,具体详情可以看官方连接

ShardingSphere

简介

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

ShardingSphere项目状态如下:

在这里插入图片描述
ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。

在这里插入图片描述

具体分为三部分:

  • Sharding-JDBC:被定位为轻量级Java框架,在Java的JDBC层提供的额外服务,以jar包形式使用。
  • Sharding-Proxy:被定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。
  • Sharding-Sidecar:被定位为Kubernetes或Mesos的云原生数据库代理,以DaemonSet的形式代
    理所有对数据库的访问。

具体之间的关系如下图所示:
我们的应用层使用Sharding-JDBC对数据进行操作,然后可以由于Sharding-Proxy进行代理,
在这里插入图片描述
Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三者区别如下:

在这里插入图片描述

Sharding-JDBC

Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架的使用。

  • 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

主要功能

数据分片

  • 分库,分表
  • 读写分离
  • 分片策略
  • 分布式主键

分布式事务

  • 标准化事务接口
  • XA强一致性事务
  • 柔性事务

数据库治理

  • 配置动态化
  • 编排和治理
  • 数据脱敏
  • 可视化链路追踪

在这里插入图片描述

图中黄色部分表示的是Sharding-JDBC的入口API,采用工厂方法的形式提供。 目前有

  • ShardingDataSourceFactory和MasterSlaveDataSourceFactory两个工厂类。
  • ShardingDataSourceFactory支持分库分表、读写分离操作
  • MasterSlaveDataSourceFactory支持读写分离操作

图中蓝色部分表示的是Sharding-JDBC的配置对象,提供灵活多变的配置方式。

  • ShardingRuleConfiguration是分库分表配置的核心和入口,它可以包含多个
  • TableRuleConfiguration和MasterSlaveRuleConfiguration。 TableRuleConfiguration封装的是表的分片配置信息,有5种配置形式对应不同的Configuration类型。
  • MasterSlaveRuleConfiguration封装的是读写分离配置信息。

图中红色部分表示的是内部对象,由Sharding-JDBC内部使用,应用开发者无需关注。ShardingJDBC通过ShardingRuleConfiguration和MasterSlaveRuleConfiguration生成真正供ShardingDataSource和MasterSlaveDataSource使用的规则对象。ShardingDataSource和MasterSlaveDataSource实现了DataSource接口,是JDBC的完整实现方案。

规则配置

Sharding-JDBC可以通过Java,YAML,Spring命名空间和Spring Boot Starter四种方式配置,开
发者可根据场景选择适合的配置方式。

创建DataSource

通过ShardingDataSourceFactory工厂和规则配置对象获取ShardingDataSource,然后即可通过
DataSource选择使用原生JDBC开发,或者使用JPA, MyBatis等ORM工具。
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, props);

数据分片理论知识

核心概念

表概念

  • 真实表
    数据库中真实存在的物理表。例如b_order0、b_order1
  • 逻辑表

在分片之后,同一类表结构的名称(总成)。例如b_order。

  • 数据节点

在分片之后,由数据源和数据表组成。例如ds0.b_order1

  • 绑定表

指的是分片规则一致的关系表(主表、子表),例如b_order和b_order_item,均按照
order_id分片,则此两个表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积
关联,可以提升关联查询效率。

b_order:b_order0、b_order1
b_order_item:b_order_item0、b_order_item1 select * from b_order o join b_order_item i on(o.order_id=i.order_id) where o.order_id in (10,11);

如果不配置绑定表关系,采用笛卡尔积关联,会生成4个SQL

select * from b_order0 o join b_order_item0 i on(o.order_id=i.order_id) where o.order_id in (10,11); select * from b_order0 o join b_order_item1 i on(o.order_id=i.order_id) where o.order_id in (10,11); select * from b_order1 o join b_order_item0 i on(o.order_id=i.order_id) where o.order_id in (10,11); select * from b_order1 o join b_order_item1 i on(o.order_id=i.order_id) where o.order_id in (10,11);

如果配置绑定表关系,生成2个SQL

select * from b_order0 o join b_order_item0 i on(o.order_id=i.order_id) where o.order_id in (10,11); select * from b_order1 o join b_order_item1 i on(o.order_id=i.order_id) where o.order_id in (10,11);

  • 广播表

在使用中,有些表没必要做分片,例如字典表、省份信息等,因为他们数据量不大,而且这种表可能需要与海量数据的表进行关联查询。广播表会在不同的数据节点上进行存储,存储的表结构和数据完全相同。

分片算法(ShardingAlgorithm)

由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。目前提供4种分片算法。

  • 精确分片算法PreciseShardingAlgorithm
    用于处理使用单一键作为分片键的=与IN进行分片的场景。
  • 范围分片算法RangeShardingAlgorithm
    用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。
  • 复合分片算法ComplexKeysShardingAlgorithm
    用于处理使用多键作为分片键进行分片的场景,多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。
  • Hint分片算法HintShardingAlgorithm
    用于处理使用Hint行分片的场景。对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释两种方式使用。

分片策略(ShardingStrategy)

分片策略包含分片键和分片算法,真正可用于分片操作的是分片键 + 分片算法,也就是分片策
略。目前提供5种分片策略。

  • 标准分片策略StandardShardingStrategy
    只支持单分片键,提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。
    提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
    PreciseShardingAlgorithm是必选的,RangeShardingAlgorithm是可选的。但是SQL中使用
    了范围操作,如果不配置RangeShardingAlgorithm会采用全库路由扫描,效率低。
  • 复合分片策略ComplexShardingStrategy
    支持多分片键。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。由
    于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片
    操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
  • 行表达式分片策略InlineShardingStrategy

只支持单分片键。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,对于
简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发。如: t_user_$->
{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

  • Hint分片策略HintShardingStrategy
    通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。
  • 不分片策略NoneShardingStrategy
    不分片的策略。

分片策略配置

对于分片策略存有数据源分片策略和表分片策略两种维度,两种策略的API完全相同。

  • 数据源分片策略

用于配置数据被分配的目标数据源。

  • 表分片策略

用于配置数据被分配的目标表,由于表存在与数据源内,所以表分片策略是依赖数据源分片策略结果的。

流程剖析

SQL解析

SQL解析分为词法解析和语法解析。 先通过词法解析器将SQL拆分为一个个不可再分的单词。再使用语法解析器对SQL进行理解,并最终提炼出解析上下文。
Sharding-JDBC采用不同的解析器对SQL进行解析,解析器类型如下:

  • MySQL解析器
  • Oracle解析器
  • SQLServer解析器
  • PostgreSQL解析器
  • 默认SQL解析器
查询优化

负责合并和优化分片条件,如OR等。

SQL路由

根据解析上下文匹配用户配置的分片策略,并生成路由路径。目前支持分片路由和广播路由。

SQL改写

将SQL改写为在真实数据库中可以正确执行的语句。SQL改写分为正确性改写和优化改写。

SQL执行

通过多线程执行器异步执行SQL。

结果归并

将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并、内存归并和使
用装饰者模式的追加归并这几种方式。

在这里插入图片描述

SQL使用规范

具体详情可以查官方说明文档点击跳转

Sharding-JDBC使用

首先引入依赖,这儿我们直接使用JPA来进行操作

			<dependency>
                <groupId>org.apache.shardingsphere</groupId>
                <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
                <version>$4.1.0</version>
            </dependency>
	
		 <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.48</version>
            </dependency>

			<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
                <version>${springboot.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
                <version>${springboot.version}</version>
            </dependency>
复制代码

首先我们来演示分表即单库中多个表,即分表策略

我们准备两个表
在这里插入图片描述

实体类

@Entity
@Table(name="position")
public class Position implements Serializable {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "salary")
    private String salary;

    @Column(name = "city")
    private String city;
//set get 省略
}
复制代码

JPA接口

public interface PositionRepository  extends JpaRepository<Position,Long> {}
复制代码

策略以及数据源配置


#打印shardingsphere sql
spring.shardingsphere.props.sql.show=true


## 分表


# 分库信息配置
spring.shardingsphere.datasource.names=test0

#配置数据库信息


#配置连接池
spring.shardingsphere.datasource.test0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test0.jdbc-url=jdbc:mysql://localhost:3306/test0
spring.shardingsphere.datasource.test0.username=root
spring.shardingsphere.datasource.test0.password=root

# 分表配置
spring.shardingsphere.sharding.tables.position.actual-data-nodes=test0.position_${0..1}

# 配置分片数据库 字段
spring.shardingsphere.sharding.tables.position.table-strategy.inline.sharding-column=id
# 配置分片规则 这儿根据id取模2 进行单库分表
spring.shardingsphere.sharding.tables.position.table-strategy.inline.algorithm-expression=position_$->{id % 2}



# 配置指定使用雪花算法生成id
#对应主键字段名
spring.shardingsphere.sharding.tables.position.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position.key-generator.type=SNOWFLAKE
复制代码
分片配置

这儿我们使用行表达式进行分片配置

  • Inline行表达式
    InlineShardingStrategy:采用Inline行表达式进行分片的配置。
    Inline是可以简化数据节点和分片算法配置信息。主要是解决配置简化、配置一体化。

具体配置

只需要在配置中使用 e x p r e s s i o n 或 { expression }或 expression或->{ expression }标识行表达式即可。例如:

在这里插入图片描述

行表达式中如果出现多个 或 {}或 或->{}表达式,整个表达式结果会将每个子表达式结果进行笛卡尔(积)组合。例如,以下行表达式:

在这里插入图片描述

最终会解析为:

在这里插入图片描述

数据节点配置:

在这里插入图片描述

分片算法配置

行表达式内部的表达式本质上是一段Groovy代码,可以根据分片键进行计算的方式,返回相应的真实数据源或真实表名称。

ds${id % 10} 
或者
ds$->{id % 10}
复制代码

表示的结果为:ds0、ds1、ds2… ds9

分布式主键

ShardingSphere不仅提供了内置的分布式主键生成器,例如UUID、SNOWFLAKE,还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。

内置主键生成器:

  • UUID
    采用UUID.randomUUID()的方式产生分布式主键。
  • SNOWFLAKE
    在分片规则配置模块可配置每个表的主键生成策略,默认使用雪花算法,生成64bit的长整型数据。

自定义主键生成器:

  • 自定义主键类,实现ShardingKeyGenerator接口
  • 按SPI规范配置自定义主键类

在Apache ShardingSphere中,很多功能实现类的加载方式是通过SPI注入的方式完成的。注意:在resources目录下新建META-INF文件夹,再新建services文件夹,然后新建文件的名字为org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator,打开文件,复制自定义主键类全路径到文件中保存。

  • 自定义主键类应用配置
#对应主键字段名 
spring.shardingsphere.sharding.tables.t_book.key-generator.column=id 
#对应主键类getType返回内容 
spring.shardingsphere.sharding.tables.t_book.key- generator.type=TestKEY
复制代码

然后测试一下分表

    @org.junit.Test
    public void insert(){


        for (int i = 0; i < 100; i++) {
            Position position = new Position();
            position.setCity("test -> " + i);
            position.setName("name"+i);
            position.setSalary("");
            positionRepository.save(position);
        }

    }
复制代码

日志可以看到

在这里插入图片描述

然后查看数据库
在这里插入图片描述

可以看到 尾号为0的表都是偶数值,尾号为1的表都是奇数,这样我们的单库分表就成功了。

在这里插入图片描述

在这里插入图片描述

但是如果对于数据量倾斜严重的数据我们应该如何取存储呢?比如上一篇博文中不同的客户对应的数据不一致,我们将数据量小的几个客户放在一张表中(或者存放原表不分离),一些多的各方一张表中。此时,分表策略就不适合我们这种业务场景,对此我们可以自己自定义一个分片测了。

自定义分表算法

# 自定义分表算法
spring.shardingsphere.sharding.tables.position.table-strategy.standard.sharding-column=name
spring.shardingsphere.sharding.tables.position.table-strategy.standard.precise-algorithm-class-name=com.udeam.config.MyPreciseShardingAlgorithm
复制代码

自定义分表策略
我们根据name来分表,0结尾的存在position_0中 1寸1 其他存3中

public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<String> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
        //availableTargetNames 表示所有的表 即 节点中配置的 spring.shardingsphere.sharding.tables.position.actual-data-nodes=test0.position_${0..4}
        System.out.println("availableTargetNames->" + availableTargetNames.toString());

        if (shardingValue.getValue().endsWith("0")) {
            return "position_0";
        } else if (shardingValue.getValue().endsWith("1")) {
            return "position_1";
        } else {
            return "position_3";
        }

    }

}
复制代码

其实这个变量集合就是我们定义的所有的表,我们可以根据自己的规则进行选择。
在这里插入图片描述

这儿的shardingValue 是我们的分片属性 ,可以根据这个属性来进行选择不同的表

在这里插入图片描述

测试一下可以看到

在这里插入图片描述

自定义主键

我们还是使用雪花算法来生成主键,只不过在配置类中使用自己的类。

Sharding中提供了自定义主键的接口

public interface ShardingKeyGenerator extends TypeBasedSPI {
    Comparable<?> generateKey();
}
复制代码

可以看到 内部默认实现了雪花算法和UUID ,还有一个TestID是我们自己定义的主键实现类

在这里插入图片描述

通过实现接口我们来自定义自己的主键策略

public class TestId implements ShardingKeyGenerator {
    @Override
    public Comparable<?> generateKey() {
        System.out.println(" ----  自定义主键 ---- ");
        return new SnowflakeShardingKeyGenerator().generateKey();
    }

    @Override
    public String getType() {
        return "TESTKEY"; //需要注定的主键类型名
    }

    @Override
    public Properties getProperties() {
        return null;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
复制代码

配置


##对应主键字段名
spring.shardingsphere.sharding.tables.position.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position.key-generator.type=TESTKEY
复制代码

还需要在类路径下指定全限定命名,文件夹和文件名是固定写死的,不能随意更改,内部的实现类名是我们自己定义的算法类。

在这里插入图片描述
测试后可以看到,打印出了我们的日志,以及编译后的sql,生成的主键

在这里插入图片描述

分库

分表解决了单库中数据量过多以及查询效率问题,并没有解决并发以及数据IO等性能,针对数据库并发以及IO等问题,我们可以进行分库操作,如上面的问题,我们可以在两个或者多个库中存储数据。

如下图,我们在test0,test1库中分别有position
在这里插入图片描述

我们可以按照主键的奇数偶数来选择存放test0,test1库中的表position

因为是两个数据库,所以我们需要使用分库策略,因为表是相同的我们不需要分表。

具体配置如下


#打印shardingsphere sql
spring.shardingsphere.props.sql.show=true





## 分库
# 分库信息配置
spring.shardingsphere.datasource.names=test0,test1

#配置数据库信息


#配置连接池
spring.shardingsphere.datasource.test0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test0.jdbc-url=jdbc:mysql://localhost:3306/test0
spring.shardingsphere.datasource.test0.username=root
spring.shardingsphere.datasource.test0.password=root


#配置连接池
spring.shardingsphere.datasource.test1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.shardingsphere.datasource.test1.username=root
spring.shardingsphere.datasource.test1.password=root


# 配置分片数据库 字段
spring.shardingsphere.sharding.tables.position.database-strategy.inline.sharding-column=id
# 配置分片规则 这儿根据id取模2 进行分库
spring.shardingsphere.sharding.tables.position.database-strategy.inline.algorithm-expression=test$->{id % 2}



# 配置指定使用雪花算法生成id
#对应主键字段名
spring.shardingsphere.sharding.tables.position.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position.key-generator.type=SNOWFLAKE
复制代码

测试

还是使用上面的测试用例

   @org.junit.Test
    public void insert(){


        for (int i = 0; i < 100; i++) {
            Position position = new Position();
            position.setCity("test -> " + i);
            position.setName("name"+i%4);
            position.setSalary("");
            positionRepository.save(position);
        }

    }
复制代码

从日志我们可以看到 偶数的存在了 test0库,奇数存在了test1

在这里插入图片描述

分库 + 垂直分表

在业务中比如我们一张大表字段很多,一些不常用的字段很少使用,而这张表有频繁更新一些常用字段,我们就使用垂直拆分将其拆成领一张表,通过主键关联。在这儿我们演示分库+垂直分表。

需要注意的是:分库中,我们尽量让分库后的表在一个数据库中,这样可以夸库事务,连接的问题,从设计上避免这些问题。

具体配置如下:

还是test0,tes1两个库,分别有表position,position_detail通过pid关联

在这里插入图片描述

在这里插入图片描述


#打印shardingsphere sql
spring.shardingsphere.props.sql.show=true





## 分库 : 拆表 + 分库
# 分库信息配置
spring.shardingsphere.datasource.names=test0,test1

#配置数据库信息


#配置连接池
spring.shardingsphere.datasource.test0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test0.jdbc-url=jdbc:mysql://localhost:3306/test0
spring.shardingsphere.datasource.test0.username=root
spring.shardingsphere.datasource.test0.password=root


#配置连接池
spring.shardingsphere.datasource.test1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.shardingsphere.datasource.test1.username=root
spring.shardingsphere.datasource.test1.password=root


# 配置分片数据库 字段
spring.shardingsphere.sharding.tables.position.database-strategy.inline.sharding-column=id
# 配置分片规则 这儿根据id取模2 进行分库分表
spring.shardingsphere.sharding.tables.position.database-strategy.inline.algorithm-expression=test$->{id % 2}


# 配置分片数据库 字段
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.sharding-column=pid
# 配置分片规则 这儿根据id取模2 进行分库 这儿使用垂直分库的id进行分库
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.algorithm-expression=test$->{pid % 2}


# 配置指定使用雪花算法生成id
#对应主键字段名
spring.shardingsphere.sharding.tables.position.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position.key-generator.type=SNOWFLAKE


#对应主键字段名
spring.shardingsphere.sharding.tables.position_detail.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position_detail.key-generator.type=SNOWFLAKE
复制代码

dao代码

public interface PositionDetailRepository extends JpaRepository<PositionDetail,Long> {
}
复制代码

实体代码

@Entity
@Table(name = "position_detail")
public class PositionDetail implements Serializable {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "pid")
    private long pid;

    @Column(name = "description")
    private String description;

//set get省略
}
复制代码

用过测试可以看到

   @org.junit.Test
    public void insert2(){


        for (int i = 0; i < 100; i++) {
            Position position = new Position();
            position.setCity("test -> " + i);
            position.setName("name"+i%4);
            position.setSalary("");
            positionRepository.save(position);


            PositionDetail positionDetail = new PositionDetail();
            positionDetail.setDescription(" 描述信息  ");
            positionDetail.setPid(position.getId()); //垂直分表 主键关联
            positionDetailRepository.save(positionDetail);
        }

    }
复制代码

可以看到 positionidposition_detail表的pid是一致的,然后position_detail表的id也是雪花算法生成

在这里插入图片描述

查看表可以看到再同库中,垂直分库是成功的。
在这里插入图片描述

分库分表

分库解决了IO以及单库的性能问题,分表解决了数据量大的问题,分库分表及解决数量大有解决并发以及IO等性能问题。

先看数据库

在这里插入图片描述
我们分两个库test0,test1 然后position表分为四个 分别以_0,_1,_2结尾四个表、test0中全部存偶数,然后再在position3个表中再分表;以position主键 垂直分表到position_detail表中。

test0中偶数,position 0,1,2中偶数再分,position_detail中偶数
test1中奇数,position 0,1,2中奇数再分,position_detail中奇数

这儿不能对4取模因为4和2是一样的。

具体的配置如下



#打印shardingsphere sql
spring.shardingsphere.props.sql.show=true





## 分库 +  分表 +  垂直分表
# 分库信息配置
spring.shardingsphere.datasource.names=test0,test1

#配置数据库信息


#配置连接池
spring.shardingsphere.datasource.test0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test0.jdbc-url=jdbc:mysql://localhost:3306/test0
spring.shardingsphere.datasource.test0.username=root
spring.shardingsphere.datasource.test0.password=root


#配置连接池
spring.shardingsphere.datasource.test1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.shardingsphere.datasource.test1.username=root
spring.shardingsphere.datasource.test1.password=root



# 笛卡尔积
# 分库分表节点 会自动映射 成 成test0 中 test0.position_0,test0.position_1,,test0.position_2, 3张表
# 分库分表节点 会自动映射 成 成test1 中 test1.position_1,test1.position_1,,test1.position_2, 3张表
spring.shardingsphere.sharding.tables.position.actual-data-nodes=test${0..1}.position_${0..3} 


# 分库 字段
spring.shardingsphere.sharding.tables.position.database-strategy.inline.sharding-column=id
# 根据position id % 2 分为两个库
spring.shardingsphere.sharding.tables.position.database-strategy.inline.algorithm-expression=test$->{id % 2}

# 分表 字段
spring.shardingsphere.sharding.tables.position.table-strategy.inline.sharding-column=id
# 分表 四个表
spring.shardingsphere.sharding.tables.position.table-strategy.inline.algorithm-expression=position_$->{id % 3}


# 配置指定使用雪花算法生成id
#对应主键字段名
spring.shardingsphere.sharding.tables.position.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position.key-generator.type=SNOWFLAKE




# 配置 position_detail 表的分库分表策略 这儿没有分表
spring.shardingsphere.sharding.tables.position_detail.actual-data-nodes=test${0..1}.position_detail

## position_detail 分库策略   根据 position id 垂直分表2个表
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.sharding-column=pid
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.algorithm-expression=test$->{pid % 2}


# position_detail 表 雪花算法id
spring.shardingsphere.sharding.tables.position_detail.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.position_detail.key-generator.type=SNOWFLAKE
复制代码

测试一下可以看到数据

![在这里插入图片描述](img-blog.csdnimg.cn/20210401233…在这里插入图片描述
oZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODM2MTM0Nw==,size_16,color_FFFFFF,t_70)

在这里插入图片描述

再看我们的 position_detail 表

在这里插入图片描述

test1我们就不看了,数据都是奇数

字典表

字典表又称为广播表,这儿的表不需要分片但是我们所有的数据又要去使用它,所以我们在每个库里都去保存一份,比如我们常用的城市表,配置表等等。

我们的城市表
在这里插入图片描述

这儿简单演示一下

Java代码

@Entity
@Table(name = "city")
public class City implements Serializable {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "province")
    private String province;
复制代码

dao层代码

public interface CityRepository extends JpaRepository<City,Long> {
}
复制代码

配置



#打印shardingsphere sql
spring.shardingsphere.props.sql.show=true





## 广播表 每个库中都存在一份
# 分库信息配置
spring.shardingsphere.datasource.names=test0,test1

#配置数据库信息


#配置连接池
spring.shardingsphere.datasource.test0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test0.jdbc-url=jdbc:mysql://localhost:3306/test0
spring.shardingsphere.datasource.test0.username=root
spring.shardingsphere.datasource.test0.password=root


#配置连接池
spring.shardingsphere.datasource.test1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.shardingsphere.datasource.test1.username=root
spring.shardingsphere.datasource.test1.password=root


spring.shardingsphere.sharding.broadcast-tables=city




#   表 雪花算法id
spring.shardingsphere.sharding.tables.city.key-generator.column=id
#对应主键类getType返回内容
spring.shardingsphere.sharding.tables.city.key-generator.type=SNOWFLAKE
复制代码

测试,我们就不看数据库了 看看日志,同一个id 分别插入test0,test1表中

在这里插入图片描述

未完待续,先睡觉,明天继续写…

猜你喜欢

转载自juejin.im/post/7231803859889979452