ShardingSphere

https://shardingsphere.apache.org/document/current/cn/overview/

官方文档将 ShardingSphere 定义为 分布式的数据库生态系统
它包含 Sharding-JDBC 和 Sharding-Proxy 两部分:

Sharding-JDBC: 在 Java 的 JDBC 层上提供额外的服务
ShardingSphere-Proxy: 透明的数据库代理

它提供的功能还是很强大,本次我们只聚焦于 Sharding-JDBC 的数据分片.
像下图所示,在 Spring-Boot 应用中,Sharding-JDBC 的角色其实是在 datasource 层,
它根据用户配置的分片规则,在接收到上层的查询请求后,对具体的数据库和表进行定位,查询返回结果给 ORM 层.

2023-03-09T07:20:15.png

所以,配置 Sharding-JDBC 的步骤也显而易见:

  • 配置 Sharding-JDBC 为 Spring 的 datasource
  • 通过 datasource 创建一个SQL 会话工厂: SQLSessionFactory
  • 将 SQLSessionFactory 配置给 ORM (我们使用 Mybatis)

2023-03-09T06:42:37.png

快速接入

配置 Sharding-JDBC

Sharding-JDBC 的配置主要包括:

数据源配置:

  • dataSources 数据源配置

规则配置:

  • defaultDatabaseStrategy:数据库分片配置
  • tables 表分片配置
  • shardingAlgorithms 分片算法配置
  • keyGenerators 主键生成算法配置
  • auditors 分片审计算法配置(暂时未用到)

我测试的项目里共有:

4个数据库实例demo_ds_0 ~ demo_ds_3
每个数据库有 6 张表t_order_0 ~ t_order_1
每个表有两个字段user_id, order_id
库的分片算法ds_${user_id % 4}
表的分片算法ds_${user_id % 6}
主键生成算法sharding-jdbc 自带的雪花算法 SNOWFLAKE

数据库分片的目标是:

将相同用户(user_id)的数据放在同一个库里,每个库里的订单表均匀分布在每张表里

下面是我测试所用的 yaml 配置:

dataSources:
  ds_xd_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  ds_2:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  ds_3:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456


rules:
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_${0..3}.t_order_${0..5}
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: t_order_inline
        keyGenerateStrategy:
          column: id
          keyGeneratorName: snowflake
    defaultDatabaseStrategy:
      standard:
        shardingColumn: user_id
        shardingAlgorithmName: database_inline

    shardingAlgorithms:
      database_inline:
        type: INLINE
        props:
          algorithm-expression: ds_${user_id % 4}
      t_order_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 6}

    keyGenerators:
      snowflake:
        type: SNOWFLAKE

配置 Spring datasource

datasource.url 指向我们上面创建的 yaml 文件

spring.datasource.driver-class-name=org.apache.shardingsphere.driver.ShardingSphereDriver
spring.datasource.url=jdbc:shardingsphere:classpath:sharding.yaml

配置 ORM (Mybatis)


首先配置 SqlSessionFactory

@Configuration
public class DataSourceConfiguration {

    @Resource
    private DataSource dataSource;


    @Bean(name = "mqSqlSessionFactory")
    public SqlSessionFactory mqSqlSessionFactory() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //实体扫描
        bean.setTypeAliasesPackage("com.kong.demo.dao.model");

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            //mapper映射文件加载
            bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
            bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
            return bean.getObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

然后配置 MapperScannerConfigurer

@Configuration
public class MyBatisMapperScannerConfiguration {

    @Bean("ubudMapperScannerConfigurer")
    public MapperScannerConfigurer ubudMapperScannerConfigurer() {
        MapperScannerConfigurer mapper = new MapperScannerConfigurer();
        mapper.setSqlSessionFactoryBeanName("mqSqlSessionFactory");
        mapper.setBasePackage("com.kong.demo.dao");
        return mapper;
    }
}

mapper 文件如下,为了测试,我加入了一个 insert 方法:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="so.dian.cs.mg.dao.OrderDAO">
    <resultMap id="BaseResultMap" type="so.dian.cs.mg.dao.model.Order">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="order_id" property="orderId" />
        <result column="user_id" property="userId" />

    </resultMap>


    <insert id="insert" parameterType="so.dian.cs.mg.dao.OrderDAO">
        insert into t_order (order_id, user_id) values (#{orderId}, #{userId})
    </insert>

</mapper>

完成上面的配置后,写一个测试接口,用不同的userId, orderId, 试着向数据库里插入数据测试,发现已经
按照预期插入了对应的库和对应的表。

总结

本期简单记录了下使用 yaml配置文件的形式,往 spring-boot 应用里接入 sharding-jdbc的过程。在实际的项目
开发中,更多还是使用 Java 配置的形式来进行数据分片的配置,后面将会分期记录分享.

文章目录