分库分表

说明

Zebra 微服务框架引入了 ShardingSphere 的 Sharding-JDBC 组件来支持分库分表功能。

Sharding-JDBC 相关说明请参考官方文档

样例

参考 TODO

开发

依赖引入

引入如下依赖

  1. <dependency>
  2. <groupId>com.guosen</groupId>
  3. <artifactId>zebra-database</artifactId>
  4. <version>${zebra.version}</version>
  5. </dependency>

注:将 ${zebra.version} 替换为使用的 Zebra 版本

配置

配置样例

  1. zebra.database.url[0]=jdbc:sqlserver://ip:port;database=dbName01
  2. zebra.database.username[0]=sa
  3. zebra.database.pwd[0]=password
  4. zebra.database.dataSourceName[0]=ds0
  5. zebra.database.url[1]=jdbc:sqlserver://ip:port;database= dbName02
  6. zebra.database.username[1]=sa
  7. zebra.database.pwd[1]=password
  8. zebra.database.dataSourceName[1]=ds1
  9. zebra.database.shardingcfg.shardDs01.datasource.names=ds0,ds1
  10. zebra.database.shardingcfg.shardDs01.basePackage=com.guosen.zebra.demo.sharding.dao
  11. zebra.database.shardingcfg.shardDs01.sharding.tables.t_credit.actual-data-nodes=ds$->{0..1}.t_credit_$->{2019..2039}0$->{1..9},ds$->{0..1}.t_credit_$->{2019..2039}$->{10..12}
  12. zebra.database.shardingcfg.shardDs01.sharding.tables.t_credit.table-strategy.inline.sharding-column=m_month
  13. zebra.database.shardingcfg.shardDs01.sharding.tables.t_credit.table-strategy.inline.algorithm-expression=t_credit_$->{m_month}
  14. zebra.database.shardingcfg.shardDs01.sharding.tables.t_credit.database-strategy.inline.sharding-column=fund_id
  15. zebra.database.shardingcfg.shardDs01.sharding.tables.t_credit.database-strategy.inline.algorithm-expression=ds$->{fund_id % 2}
  16. zebra.database.shardingcfg.shardDs01.props.sql.show=true

如上图,上述配置项配置了一个逻辑表 t_credit 的分库分表规则。

三个关键的配置项说明如下:

  • zebra.database.shardingcfg.shardDs01.datasource.names

    组成分库分表的原始数据源名称,一个到多个,以逗号分隔。

    比如上述配置

      zebra.database.shardingcfg.shardDs01.datasource.names=ds0,ds1
    

    ds0 对应数据源配置项 zebra.database.dataSourceName[0]=ds0 的值。

    ds1 对应数据源配置项 zebra.database.dataSourceName[1]=ds1 的值。

  • t_credit.database-strategy相关的配置项

    配置了分库规则

    t_credit.database-strategy.inline.algorithm-expression=ds$->{fund_id%2}表示根据 SQL 中的 fund_id 字段对 2 取模来确定该 SQL 要路由到哪个数据源对应的数据库执行。

    比如 SQL

      select * from t_credit where m_month = 201908 and fund_id = 8888
    

    那么最后分库 SQL 会变为(仍和上面分表 SQL 一致)

      select * from t_credit_201908 where m_month = 201908 and fund_id = 8888
    

    路由到的数据源为ds$->{8888%2} = ds0,该 SQL 会被路由到 ds0 对应的数据库中执行。

  • t_credit.table-strategy 相关的配置项

    配置了分表规则

    tcredit.table-strategy.inline.algorithm-expression=t_credit$->{m_month} 表示根据SQL中 m_month 进行分表。

    比如 SQL

      select * from t_credit where m_month = 201908 and fund_id = 8888
    

    那么最后分表 SQL 会变为

      select * from t_credit_201908 where m_month = 201908 and fund_id = 8888
    

配置说明

和 Sharding-JDBC 基本保持一致,但是配置前缀修改为 zebra.database.shardingcfg.${分库分表数据源名称}

关键配置项

配置项 说明
datasources.name 组成分库分表的原始数据源名称,一个到多个,以逗号分隔。 原始数据源名称为 zebra.database.dataSourceName[k]=dsName 对应的值
basePackage 分库分表对应 MyBatis 的 basePackage,此为 Zebra 定制配置项
tables.tableName.actual-data-nodes 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。缺省表示使用已知数据源与逻辑表名称生成数据节点。用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
props.sql.show 表示是否开启分库分表SQL打印。 true : 开启; false : 不开启(默认值) 开启时,会打印出逻辑SQL和分库分表之后实际的SQL。一般用于开发阶段的问题定位。生产环境不要打开此开关
其他配置项 参考 ShardingSphere SpringBoot 配置,将前缀“spring.shardingsphere”修改为 zebra 的前缀“zebra.database.shardingcfg.${分库分表数据源名称}” 即可。

代码

代码开发和已有 Zebra 数据库开发方式保持一致。但是相关业务 SQL 必须带上分库分表字段,如果没有带,则 Sharding-JDBC 会扫描配置的所有表,速度很可能就非常慢。

相关限制

参考官方文档 1. 不支持的sql 2. JDBC不支持项

下面仅列出 Zebra 开发验证时发现的问题。

SQLServer 的限制

如果使用的数据为 SQLServer,则应该注意如下问题。

  • 分页

    Sharding-JDBC 对 SQLServer 的分页支持不完整,官网宣称可以 2 种分页方式:TOP + ROWNUMBER和 OFFSET FETCH。经验证,2 种都有不同程度的 bug。 分页查询当前实际只支持 OFFSET FETCH 方式,必须同时带上包含了分表分库字段的 where 条件,若不带分库分表字段条件,则返回的数据可能会比实际的多。

    已经在 GitHub 上面提了 issue

    1. SQLServer OFFSET FETCH pagination return wrong results
    2. SQLServer TOP + ROW_NUMBER() pagination SQL error
  • 字段不能为 SQLServer 保留字

    当字段名称和保留字一样时,Sharding-JDBC 解析业务 SQL 会报错,但仅仅只是打印错误信息,不终止后续步骤,分库分表会失效,变成在逻辑表的所有物理表上执行 SQL。所以使用分库分表的表,一定不能使用保留字作为字段名称(其实不使用分库分表也应该遵循这个规则)。