1 概述

本文次要讲述了如何应用ShardingSphere(其中的Sharding-JDBC)和MyBatisPlus进行分库分表,具体步骤包含:

  • 筹备数据库环境
  • 筹备依赖
  • 编写配置文件
  • 测试

2 筹备数据库环境

2.1 两库六表

筹备好两个库:

  • test0
  • test1

在两个库中别离建设三个字段一样的表:

  • user0
  • user1
  • user2

字段如下:

这样就筹备了两个库以及其中的六个表了。

2.2 (可选)MyBatis Plus Generator代码生成表

因为MyBatis Plus Generator生成的Controller等代码默认是依照表名命名的,这样就会生成相似User0User0Controller这样的命名,因而这里创立一个叫user的表,仅仅用于代码的生成,外面不会寄存任何的数据:

3 新建我的项目

新建Spring Boot我的项目并引入如下依赖:

  • Druid
  • MyBatis Plus starter
  • MyBaits Plus Generator
  • Velocity core
  • ShardingSphere
  • Yitter(一个雪花id生成器)

Maven如下:

<dependency>    <groupId>com.baomidou</groupId>    <artifactId>mybatis-plus-boot-starter</artifactId>    <version>3.4.3.1</version></dependency><dependency>    <groupId>com.baomidou</groupId>    <artifactId>mybatis-plus-generator</artifactId>    <version>3.5.0</version></dependency><dependency>    <groupId>org.apache.velocity</groupId>    <artifactId>velocity-engine-core</artifactId>    <version>2.3</version></dependency><dependency>    <groupId>org.realityforge.org.jetbrains.annotations</groupId>    <artifactId>org.jetbrains.annotations</artifactId>    <version>1.7.0</version></dependency><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version>1.2.6</version></dependency><dependency>    <groupId>org.apache.shardingsphere</groupId>    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>    <version>4.1.1</version></dependency><dependency>    <groupId>com.github.yitter</groupId>    <artifactId>yitter-idgenerator</artifactId>    <version>1.0.6</version></dependency>

Gradle如下:

implementation 'com.baomidou:mybatis-plus-boot-starter:3.4.3.1'implementation 'org.apache.velocity:velocity-engine-core:2.3'implementation 'org.realityforge.org.jetbrains.annotations:org.jetbrains.annotations:1.7.0'implementation 'com.alibaba:druid:1.2.6'implementation 'org.apache.shardingsphere:sharding-jdbc-spring-boot-starter:4.1.1'implementation 'com.github.yitter:yitter-idgenerator:1.0.6'

4 配置文件

配置文件能够参考ShardingSphere文档,这里给出一个示例配置:

spring:  datasource:    url: jdbc:mysql://127.0.0.1:3306/test                       # spring 数据源    username: root                                              # 用户名    password: 123456                                            # 明码  shardingsphere:    datasource:      names: test0,test1                                        # 数据源,这里为了不便间接应用库名的名称      test0:                                                           type: com.alibaba.druid.pool.DruidDataSource            # Druid连接池        url: jdbc:mysql://127.0.0.1:3306/test0                  # 连贯test0的url        username: root        password: 123456      test1:        type: com.alibaba.druid.pool.DruidDataSource            # Druid连接池        url: jdbc:mysql://127.0.0.1:3306/test1                  # 连贯test1的url        username: root        password: 123456    sharding:      default-database-strategy:                                # 默认分库策略        inline:            sharding-column: age                                  # 示意依据age列进行分库          algorithm-expression: test$->{age % 2}                # 依据age对2的模进行分库,模为0示意test0库,模为1示意test1库      tables:        user:          actual-data-nodes: test$->{0..1}.user$->{0..2}        # 表的名字,test$->{0..1}能够示意test0、test1两个库                                                                # user$->{0..2}示意user0、user1、user2三个库          table-strategy:                                       # 分表策略            inline:              sharding-column: id                               # 依据哪一列进行分表,id示意依据列名为"id"的列分表              algorithm-expression: user$->{id%3}               # 分表规定为id对3取模,id%3为0示意分到user0表                                                                # id%3为1示意分到user1表,id%3为2示意分到user2表    props:      sql:        show:          true                                                  # 打印sql

这里应用主动取模分片策略,ShardingShphere内置了如下分片算法:

  • 主动分片算法:取模分片、哈希取模分片、基于分片容量的范畴分片、基于分片边界的范畴分片、主动时间段分片
  • 规范分片算法:行表达式分片、工夫范畴分片
  • 复合行表达式分片
  • Hint行表达式分片

如果不能满足需要还能够自定义分片算法,具体请看官网文档。

5 测试代码生成

应用MyBaits Plus Generator生成相应代码,具体应用能够参考笔者之前的文章,这里间接放上生成类的代码:

import com.baomidou.mybatisplus.generator.AutoGenerator;import com.baomidou.mybatisplus.generator.config.*;public class MyBatisPlusGenerator {    public static void main(String[] args) {        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:mysql://localhost:3306/test0", "root", "123456").build();        String projectPath = System.getProperty("user.dir");        StrategyConfig strategyConfig = new StrategyConfig.Builder().addInclude("user").build();        GlobalConfig globalConfig = new GlobalConfig.Builder().outputDir(projectPath + "/src/main/java").openDir(false).build();        PackageConfig packageConfig = new PackageConfig.Builder().moduleName("user").parent("com.example.demo").serviceImpl("service").build();        new AutoGenerator(dataSourceConfig).global(globalConfig).packageInfo(packageConfig).strategy(strategyConfig).execute();    }}

UserController类批改如下:

@RestController@RequestMapping("/user")@RequiredArgsConstructor(onConstructor = @__(@Autowired))public class UserController {    private final Random random = new Random();    private final UserServiceImpl service;    @GetMapping("/select")    public List<User> select(){        return service.list();    }    @GetMapping("/insert")    public boolean insert(){        return service.save(User.builder().age(random.nextInt(80)+20).name("test name").email("test@test.com").build());    }}

6 减少雪花id生成器

首先批改User类,减少一个@Builder注解,同时批改id的生成策略,应用IdType.ASSIGN_ID

@Builderpublic class User implements Serializable {    @TableId(type = IdType.ASSIGN_ID)    private Long id;    //...}

新建id生成器类:

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;import com.github.yitter.contract.IdGeneratorOptions;import com.github.yitter.idgen.YitIdHelper;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Componentpublic class IdGenerator implements IdentifierGenerator {    final IdGeneratorOptions options = new IdGeneratorOptions((short) 1);    @PostConstruct    public void init() {        YitIdHelper.setIdGenerator(options);    }    @Override    public Long nextId(Object entity) {        return YitIdHelper.nextId();    }}

这样生成id的时候,就会主动调用nextId()办法,其中的id生成器能够依据须要进行替换,换成其余雪花id生成器或分布式id生成器。

配置的时候能够参考MyBaits Plus 自定义ID生成器文档。

7 测试

先随机插入三条数据,刷新三次如下页面:

localhost:8080/test/user/insert

能够看到执行了三次插入操作,插入的三个表别离是:

  • test0.user2
  • test0.user0
  • test0.user2

因为这里测试的时候年龄都恰好是偶数,都插入到了test0表。

查看数据:

http://localhost:8080/user/select

日志输入如下:

示意这是对六个表查问的后果,并将最初的后果进行聚合返回。

8 参考源码

Java版:

  • Github
  • 码云
  • CODE.CHINA

Kotlin版:

  • Github
  • 码云
  • CODE.CHINA