2、ShardingSphere之测试jdbc

2,024 阅读3分钟

本系列的原码对应:ShardingSphere-5.0.0-beta

1、说明

本次将会通过examples里面提供的测试用例开始shardingsphere的学习。

2、添加examples项目

examples项目默认未被maven加载,通过idea右边maven +号,把examples目录导进来

3、初始化数据库

3.1、初始化示例数据库

在examples/src/resources目录下,我们可以看到一个manual_schema.sql的文件,执行该数据库脚本后,即可完成示例数据库的初始化

我的环境是vm中的docker mysql5.7,直接通过Navicat Premium连接上数据库,执行该脚本,这部分没有要求,我用的是mysql数据库,shardingsphere jdbc目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 标准的数据库。

image.png

3.2、修改连接信息

要想运行demo需要先修改jdbc的配置,分为DataSourceUtil类和yaml配置两种,自行选择

在examples->shardingsphere-jdbc-example->sharding-example->sharding-raw-jdbc-example下

image.png

修改examples->example-core->example-api中的DataSourceUtil类

image.png 修改resources->sharding-databases.yaml文件,其余文件一样,用到哪个修改哪个

image.png

4、ShardingSphere jdbc 功能测试

image.png 根据测试类进入OrderServeiceImpl类中,进行断点观看运行情况,对processSuccess方法进行断点跟踪

ps:断点的意义在于,测试用例会删除数据,不通过断点无法清晰的看到运行效果

image.png

4.1、分库示例

代码默认即为分库

private static ShardingType shardingType = ShardingType.SHARDING_DATABASES;

分库规则

rules:
- !SHARDING
  tables:
    t_order: 
      actualDataNodes: ds_${0..1}.t_order
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  broadcastTables:
    - t_address
  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    none:
  
  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    
  keyGenerators:
    snowflake:
      type: SNOWFLAKE
      props:
          worker-id: 123

props:
  sql-show: false

从ds_${user_id % 2};这句配置可以看到,是按user_id对2取模来确定放到哪个库。

image.png

4.2、分表示例

使用分表

private static ShardingType shardingType = ShardingType.SHARDING_TABLES;

分表规则

rules:
- !SHARDING
  tables:
    t_order: 
      actualDataNodes: ds.t_order_${0..1}
      tableStrategy: 
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds.t_order_item_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  broadcastTables:
    - t_address
  
  shardingAlgorithms:
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${order_id % 2}
  
  keyGenerators:
    snowflake:
      type: SNOWFLAKE
      props:
          worker-id: 123

props:
  sql-show: false

可以看到t_order和t_order_item表分别模2的规则进行数据分表

image.png

发现分表失败,数据并未按id取模,经过分析发现取模规则是order_id,改为对user_id字段取模即可

修改sharding-tables.yaml:

shardingColumn: user_id
algorithm-expression: t_order_${user_id % 2}

image.png

4.3、分库分表示例

使用分库分表

private static ShardingType shardingType = ShardingType.SHARDING_DATABASES_AND_TABLES;

分库分表规则

rules:
- !SHARDING
  tables:
    t_order: 
      actualDataNodes: ds_${0..1}.t_order_${0..1}
      tableStrategy: 
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  broadcastTables:
    - t_address
  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    none:
  
  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${order_id % 2}
  
  keyGenerators:
    snowflake:
      type: SNOWFLAKE
      props:
          worker-id: 123

props:
  sql-show: false

可以看到, 默认分库算法是对user_id按2取模;分表算法也都是按各自的id按2取模,就是简单的路由下。

image.png

和分表一样存在配置上的问题,改动如下:

rules:
- !SHARDING
  tables:
    t_order:
      actualDataNodes: ds_${0..1}.t_order_${0..3}
      tableStrategy:
        standard:
          shardingColumn: user_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..3}
      tableStrategy:
        standard:
          shardingColumn: user_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item

  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: t_order_inline

  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${user_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${user_id % 2}

image.png 存在的问题是每个库都冗余出了2张表,还是没能达到预期,后面尝试使用address_id进行分表,使用user_id进行分库,会出错大致意思应该是不支持同时使用2个字段进行路由。这边猜测应该是我对分库分表理解不到位。

Exception in thread "main" org.apache.shardingsphere.infra.exception.ShardingSphereException: Insert statement does not support sharding table routing to multiple data nodes.

4.4、读写分离示例

使用读写分离

private static ShardingType shardingType = ShardingType.READWRITE_SPLITTING;

我的测试环境:通过docker模拟2台mysql服务器,设置主从同步

1、master 192.168.10.135:3310 (docker1)
2、salve 192.168.10.135:3311 (docker2)

读写分离规则

dataSources:
  write_ds:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.10.135:3310/demo_write_ds?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  read_ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.10.135:3311/demo_write_ds?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456

rules:
- !READWRITE_SPLITTING
  dataSources:
    pr_ds:
      writeDataSourceName: write_ds
      readDataSourceNames: [read_ds_0]

props:
  sql-show: false

image.png

为了验证读写分离,我将slave数据库中同步到的数据进行删除,发现printData();打印出来的数据的确是slave中的,至此读写分离测试完成

4.5、加密示例

在examples->shardingsphere-jdbc-example->other-feature-example->encrypt-example->encrypt-raw-jdbc-example下

image.png

老套路断点UserServiceImpl类中processSuccess方法

记得修改数据库连接 encrypt-databases.yaml

加密规则:

rules:
- !ENCRYPT
  tables:
    t_user:
      columns:
        user_name:
          plainColumn: user_name_plain
          cipherColumn: user_name
          encryptorName: name_encryptor
        pwd:
          cipherColumn: pwd
          assistedQueryColumn: assisted_query_pwd
          encryptorName: pwd_encryptor
  encryptors:
    name_encryptor:
      type: AES
      props:
        aes-key-value: 123456abc
    pwd_encryptor:
      type: assistedTest

image.png

3.6、rule 规则说明

tables:  #数据分片规则配置,可配置多个logic_table_name(比如:t_order)
    t_order:  #逻辑表名
      actualDataNodes: ds_${0..1}.t_order  #真实数据节点(数据库中真实表名)
      keyGenerateStrategy:  #主键生成策略
        column: order_id  #主键名
        keyGeneratorName: snowflake
bindingTables: #绑定表,即分片规则一致的关系表,互为绑定表关系。绑定表之间的多表关联
查询不会出现笛卡尔积关联,可以提升关联查询效率。
broadcastTables: #广播表,即在所有的库中都存在的基础表,防止跨库查询
    - t_address
defaultDatabaseStrategy:  #默认数据库分片策略
    standard:  #用于单分片键的标准分片场景
    shardingColumn: user_id #分片列名称
    shardingAlgorithmName: database_inline
defaultTableStrategy:  #默认表分片策略,同分库策略
   none:
     
shardingAlgorithms:
  database_inline:
    type: INLINE
    props:
      algorithm-expression: ds_${user_id % 2}

总结

本次主要是通过对examples模块中的sharding jdbc的运行,来寻找突破口了解和学习shardingsphere原码。测试了jdbc模块的分库、分表、读写分离、密码加密等功能,demo中还有jpa和mybatis版,也是对上诉功能的测试用例,其原理大同小异,并未深入探究。本次主要是对rules的yaml配置进行了深入学习,通过修改掌握了配置参数的设置,并发现inline的配置方式既简洁又高效。