当前位置:   article > 正文

ShardingSphere之分库&分表_shardingspheredatasourcefactory.createdatasource

shardingspheredatasourcefactory.createdatasource

笔者日常看朋友发了一篇关于ShardingSphere的文章,我对ShardingSphere挺感兴趣的,于是就学了下。


目录

辅助理解

【分库分表示例】之需求与库表说明

          需求说明

          需求相关表

【分库分表示例】之代码实现

          准备工作

          Sharding分片配置

测试一下

          测试准备

          编写测试方法

          进行测试


ShardingSphere功能强大,本文学习使用Sharding-JDBC数据分片功能下的分库分表功能。

辅助理解

注:由于本文知识需要,所以上图做了一个简单说明。

注:本文会涉及到的一些ShardingSphere基础概念,建议先去https://shardingsphere.apa.../sharding/了解一下。


【分库分表示例】之需求与库表说明

需求说明

       将职工按照不同的年龄段进行分库,按照不同的性别进行分表。具体需求为:age在[0, 50)的,分到younger库;age在[50, 100)的,分到older库;age>=100的,分到other库。其中younger库和older库又按照性别进行分表,男的录入staff_man表,女的录入staff_woman表,other库不区分男女,不论男女都直接录入staff表。

注:本文以实现此需求进行分库分表示例

需求相关库表

上图中的相关表,建表语句为:

  1. CREATE TABLE `staff_man` (
  2. `id` varchar(40) NOT NULL,
  3. `age` int(3) DEFAULT NULL,
  4. `name` varchar(10) DEFAULT NULL,
  5. `gender` char(1) DEFAULT NULL,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  8. CREATE TABLE `staff_woman` (
  9. `id` varchar(40) NOT NULL,
  10. `age` int(3) DEFAULT NULL,
  11. `name` varchar(10) DEFAULT NULL,
  12. `gender` char(1) DEFAULT NULL,
  13. PRIMARY KEY (`id`)
  14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  15. CREATE TABLE `staff` (
  16. `id` varchar(40) NOT NULL,
  17. `age` int(3) DEFAULT NULL,
  18. `name` varchar(10) DEFAULT NULL,
  19. `gender` char(1) DEFAULT NULL,
  20. PRIMARY KEY (`id`)
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

注:这里先按照需求进行建库建表。

注:建库建表可以使用程序动态创建,不过考虑到本节知识主要讲述ShardingSphere分库分表的实现,就不再引
       入其它知识来干扰主题了,所以这里手动创建库表。


【分库分表示例】之代码实现

软硬件环境说明:Windows10、IntelliJ IDEA、SpringBoot 2.1.4.RELEASE、MySQL、MyBatis。

准备工作

在pom.xml中引入ShardingSphere分库分表依赖

这里直接给出本人完整的pom.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.4.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.aspire</groupId>
  12. <artifactId>sharding-database-table</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>sharding-database-table</name>
  15. <description>分库分表示例</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-test</artifactId>
  27. <scope>test</scope>
  28. </dependency>
  29. <!-- lombok -->
  30. <dependency>
  31. <groupId>org.projectlombok</groupId>
  32. <artifactId>lombok</artifactId>
  33. <optional>true</optional>
  34. </dependency>
  35. <!--mybatis-->
  36. <dependency>
  37. <groupId>org.mybatis.spring.boot</groupId>
  38. <artifactId>mybatis-spring-boot-starter</artifactId>
  39. <version>2.0.0</version>
  40. </dependency>
  41. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  42. <dependency>
  43. <groupId>mysql</groupId>
  44. <artifactId>mysql-connector-java</artifactId>
  45. <version>8.0.15</version>
  46. </dependency>
  47. <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  48. <dependency>
  49. <groupId>com.alibaba</groupId>
  50. <artifactId>druid</artifactId>
  51. <version>1.1.10</version>
  52. </dependency>
  53. <!-- https://mvnrepository.com/artifact/io.shardingjdbc/sharding-jdbc-core -->
  54. <dependency>
  55. <groupId>io.shardingjdbc</groupId>
  56. <artifactId>sharding-jdbc-core</artifactId>
  57. <version>2.0.3</version>
  58. </dependency>
  59. </dependencies>
  60. <build>
  61. <plugins>
  62. <plugin>
  63. <groupId>org.springframework.boot</groupId>
  64. <artifactId>spring-boot-maven-plugin</artifactId>
  65. </plugin>
  66. </plugins>
  67. </build>
  68. </project>

Sharding分片配置

提示Sharding分片配置有四种方式

  • Java配置

  • Yaml配置

  • SpringBoot配置

  • Spring命名空间配置

注:可详见https://shardingsphere.apache.or...onfiguration/

注:本人这里采用Java配置,是因为Java配置相对于其余三种方式来说,更容易让人理解,但是代价是与代
       码耦合度较高。如果比较熟了,推荐使用Yaml配置、SpringBoot配置。

本人Sharding分片配置的相关类说明

  • ShardingConfig:核心sharding分片配置类。该类中的主要配置步骤是:
    第一步: 获取众多数据源。
    第二步: 获取总配置类。
    第三步: 获取其余配置信息(如果需要的话)。
    第四步:定制指定逻辑表的切片(分库分表)策略。
    第五步:将定制了自己的切片策略的表的配置规则,加入总配置中。
    第六步:创建并返回sharding总数据源,注入容器。

  • DatabaseShardingAlgorithm:本人用于数据源分片的算法实现,为ShardingConfig服务。

  • StaffTableComplexKeysShardingAlgorithm:本人用于逻辑表分片的算法实现,为ShardingConfig服务。

  • StaffTableTableShardingAlgorithm:本人用于逻辑表分片的算法实现,为ShardingConfig服务。

注:StaffTableComplexKeysShardingAlgorithm和StaffTableTableShardingAlgorithm都是用于对同一个逻辑表
       分片的算法实现,在这次的示例项目汇总,其实一个就够了,不过本人这里将两个常用的都进行了实现,
       分别实现的是复合分片算法、精准分片算法。

本人Sharding分片配置的相关类的具体代码

ShardingConfig:

  1. import com.alibaba.druid.pool.DruidDataSource;
  2. import com.aspire.shardingdatabasetable.config.algorithm.DatabaseShardingAlgorithm;
  3. import com.aspire.shardingdatabasetable.config.algorithm.StaffTableComplexKeysShardingAlgorithm;
  4. import com.aspire.shardingdatabasetable.config.algorithm.StaffTableTableShardingAlgorithm;
  5. import io.shardingjdbc.core.api.ShardingDataSourceFactory;
  6. import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
  7. import io.shardingjdbc.core.api.config.TableRuleConfiguration;
  8. import io.shardingjdbc.core.api.config.strategy.ComplexShardingStrategyConfiguration;
  9. import io.shardingjdbc.core.api.config.strategy.StandardShardingStrategyConfiguration;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import javax.sql.DataSource;
  13. import java.sql.SQLException;
  14. import java.util.*;
  15. import java.util.concurrent.ConcurrentHashMap;
  16. /**
  17. * 分库分表配置
  18. *
  19. * @author JustryDeng
  20. * @date 2019/5/30 9:54
  21. */
  22. @Configuration
  23. public class ShardingConfig {
  24. /**
  25. * 切片配置
  26. *
  27. * @return 数据源
  28. * @date 2019/5/30 21:04
  29. */
  30. @Bean
  31. public DataSource shardingCustomer() throws SQLException {
  32. // 第一步: 获取众多数据源
  33. Map<String, DataSource> dataSourceMap = getDatasourceMap();
  34. // 第二步: 获取总配置类
  35. ShardingRuleConfiguration shardingRuleConfig = getShardingRuleConfiguration();
  36. // 第三步: 获取其余配置信息(如果需要的话)
  37. Properties properties = getProperties();
  38. // 第四步: 定制指定逻辑表的切片(分库分表)策略
  39. List<TableRuleConfiguration> allTableRuleConfiguration = getAllTableRuleConfiguration();
  40. // 第五步: 将定制了自己的切片策略的表的配置规则,加入总配置中
  41. shardingRuleConfig.getTableRuleConfigs().addAll(allTableRuleConfiguration);
  42. // 第六步: 创建并返回sharding总数据源,注入容器
  43. return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig,
  44. new ConcurrentHashMap<>(16), properties);
  45. }
  46. /**
  47. * 对指定逻辑表进行切片(分库分表)个性化配置
  48. * 注:本人这里只配置了
  49. *
  50. * @return 定制的 指定表的分库分表配置
  51. * @date 2019/6/4 12:01
  52. */
  53. private List<TableRuleConfiguration> getAllTableRuleConfiguration() {
  54. List<TableRuleConfiguration> list = new ArrayList<>(8);
  55. // 配置staff表切片规则
  56. TableRuleConfiguration staffTableRuleConfig = new TableRuleConfiguration();
  57. // 逻辑表名
  58. staffTableRuleConfig.setLogicTable("staff");
  59. /*
  60. * 真实库表名
  61. *
  62. * 注:库与表之间使用【.】分割;
  63. * 注:库表与库表之间使用【,】分割
  64. * 下述inline表达式的结果即为 otherDb.staff, youngerDb.staff_man, youngerDb.staff_woman, olderDb.staff_man, olderDb.staff_woman
  65. */
  66. staffTableRuleConfig.setActualDataNodes("otherDb.staff, ${['youngerDb', 'olderDb']}.staff_${['man', 'woman']}");
  67. // 设置这张表的 分库策略(本人这里采用:标准分片策略)
  68. staffTableRuleConfig.setDatabaseShardingStrategyConfig(
  69. new StandardShardingStrategyConfiguration("age", DatabaseShardingAlgorithm.class.getName()));
  70. // 设置这张表的 分表策略(本人这里采用:精确分片算法实现的标准分片策略)
  71. StandardShardingStrategyConfiguration standardShardingStrategyConfiguration = new StandardShardingStrategyConfiguration(
  72. "gender", StaffTableTableShardingAlgorithm.class.getName(), null);
  73. staffTableRuleConfig.setTableShardingStrategyConfig(standardShardingStrategyConfiguration);
  74. list.add(staffTableRuleConfig);
  75. return list;
  76. }
  77. /**
  78. * 获取其余配置信息
  79. *
  80. * @return 其余配置信息
  81. * @date 2019/6/4 11:24
  82. */
  83. private Properties getProperties() {
  84. Properties properties = new Properties();
  85. // 打印出分库路由后的sql
  86. properties.setProperty("sql.show", "true");
  87. return properties;
  88. }
  89. /**
  90. * 获取切片总配置类
  91. *
  92. * @return 总配置类
  93. * @date 2019/6/4 11:24
  94. */
  95. private ShardingRuleConfiguration getShardingRuleConfiguration() {
  96. // sharding总配置类
  97. ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
  98. // 设置全局默认库
  99. shardingRuleConfig.setDefaultDataSourceName("otherDb");
  100. // 设置全局默认分库的策略(本人这里采用:精确分片算法实现的标准分片策略)
  101. // 如果某个表,没有指定分库策略的话,那么会默认使用这个策略;如果某个表制定了自己的策略,那么就会走自己的策略不走这个默认策略
  102. shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(
  103. new StandardShardingStrategyConfiguration("age", DatabaseShardingAlgorithm.class.getName()));
  104. // 设置全局默认分表的策略(本人这里采用:复合分片策略)
  105. // 如果某个表,没有指定分表策略的话,那么会默认使用这个策略;如果某个表制定了自己的策略,那么就会走自己的策略不走这个默认策略
  106. ComplexShardingStrategyConfiguration complexShardingStrategyConfiguration = new ComplexShardingStrategyConfiguration(
  107. "age, gender", StaffTableComplexKeysShardingAlgorithm.class.getName());
  108. shardingRuleConfig.setDefaultTableShardingStrategyConfig(complexShardingStrategyConfiguration);
  109. return shardingRuleConfig;
  110. }
  111. /**
  112. * 获取数据源Map
  113. *
  114. * @return 获取数据源Map
  115. * @date 2019/6/4 10:06
  116. */
  117. private Map<String, DataSource> getDatasourceMap() {
  118. // 真实数据源map
  119. Map<String, DataSource> dataSourceMap = new HashMap<>(4);
  120. // 配置第一个数据源,对应库other
  121. DruidDataSource dataSourceDefault = new DruidDataSource();
  122. dataSourceDefault.setDriverClassName("com.mysql.cj.jdbc.Driver");
  123. dataSourceDefault.setUrl("jdbc:mysql://localhost:3306/other?characterEncoding=utf8&serverTimezone=GMT%2B8");
  124. dataSourceDefault.setUsername("root");
  125. dataSourceDefault.setPassword("dengshuai");
  126. dataSourceMap.put("otherDb", dataSourceDefault);
  127. // 配置第二个数据源,对应库younger
  128. DruidDataSource dataSourceYounger = new DruidDataSource();
  129. dataSourceYounger.setDriverClassName("com.mysql.cj.jdbc.Driver");
  130. dataSourceYounger.setUrl("jdbc:mysql://localhost:3306/younger?characterEncoding=utf8&serverTimezone=GMT%2B8");
  131. dataSourceYounger.setUsername("root");
  132. dataSourceYounger.setPassword("dengshuai");
  133. dataSourceMap.put("youngerDb", dataSourceYounger);
  134. // 配置第三个数据源,对应库older
  135. DruidDataSource dataSourceOlder = new DruidDataSource();
  136. dataSourceOlder.setDriverClassName("com.mysql.cj.jdbc.Driver");
  137. dataSourceOlder.setUrl("jdbc:mysql://localhost:3306/older?characterEncoding=utf8&serverTimezone=GMT%2B8");
  138. dataSourceOlder.setUsername("root");
  139. dataSourceOlder.setPassword("dengshuai");
  140. dataSourceMap.put("olderDb", dataSourceOlder);
  141. return dataSourceMap;
  142. }
  143. }

DatabaseShardingAlgorithm:

  1. import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
  2. import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
  3. import java.util.Collection;
  4. /**
  5. * 数据源分片策略
  6. *
  7. * 注:本人这里采用的是【精确分片算法PreciseShardingAlgorithm】,类似的算法还有
  8. * 【范围分片算法】
  9. * 【复合分片算法】
  10. * 【Hint分片算法】
  11. *
  12. * @author JustryDeng
  13. * @date 2019/5/31 10:11
  14. */
  15. public class DatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
  16. /**
  17. * Sharding.
  18. *
  19. * @param availableTargetNames
  20. * 数据源(库)名称集合 或 真实表名称集合。
  21. *
  22. * 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
  23. *
  24. * 注:这里为: 数据源(库)名称集合。
  25. * 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
  26. * 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
  27. *
  28. * 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
  29. * 以本人的此项目的库与表进行说明:
  30. * otherDb库只有表staff.
  31. * youngerDb库有表staff_man。staff_woman.
  32. * olderDb库有表staff_man。staff_woman.
  33. * 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
  34. * otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
  35. * 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
  36. * 真实表集合里只有staff_man和staff_woman;
  37. *
  38. * @param shardingValue
  39. * 分片键的值。
  40. * 如:本人此次示例中,要路由到那个数据库源,是由age为数据源分片键的,age的列类型为int,
  41. * 所以这里的泛型是Integer。
  42. * 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
  43. * 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
  44. *
  45. * @return 路由后的SQL要使用的数据源(库)的名字 或 路由后的SQL要使用的真实表的名字
  46. * 注:这里为: 路由后的SQL要使用的数据源(库)的名字。
  47. */
  48. @Override
  49. public String doSharding(Collection<String> availableTargetNames,
  50. PreciseShardingValue<Integer> shardingValue) {
  51. double value = shardingValue.getValue() * 1.0 / 50;
  52. // 年龄在[0, 50)之间的,入youngerDb库
  53. if (value < 1) {
  54. return "youngerDb";
  55. // 年龄在[50, 100)之间的,入olderDb库
  56. } else if (value < 2) {
  57. return "olderDb";
  58. // 年龄在>=100的,入otherDb库
  59. } else {
  60. return "otherDb";
  61. }
  62. /// 注:如果数据源的名称有规律的话(P.S.该名称是我们自己起的,当然可以起得很有规律),
  63. /// 也可以动态将 分片建的值 与 对应 数据源名称关联起来,如
  64. // for (String each : availableTargetNames) {
  65. //
  66. // if (each.endsWith(shardingValue.getValue() % 2 + "")) {
  67. // return each;
  68. // }
  69. // }
  70. // throw new UnsupportedOperationException();
  71. }
  72. }

StaffTableComplexKeysShardingAlgorithm:

  1. import io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue;
  2. import io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;
  3. import io.shardingjdbc.core.api.algorithm.sharding.complex.ComplexKeysShardingAlgorithm;
  4. import java.util.*;
  5. /**
  6. * 自定义符合分片策略
  7. *
  8. * 用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行
  9. * 处理其中的复杂度。需要配合ComplexShardingStrategy使用。
  10. *
  11. * @author JustryDeng
  12. * @date 2019/5/31 10:11
  13. */
  14. public class StaffTableComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm {
  15. /**
  16. * Sharding.
  17. *
  18. * @param availableTargetNames
  19. * 可用的数据源(库)名称集合 或 可用的真实表名称集合。
  20. *
  21. * 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
  22. *
  23. * 注:这里为: 数据源(库)名称集合。
  24. * 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
  25. * 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
  26. *
  27. * 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
  28. * 以本人的此项目的库与表进行说明:
  29. * otherDb库只有表staff.
  30. * youngerDb库有表staff_man。staff_woman.
  31. * olderDb库有表staff_man。staff_woman.
  32. * 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
  33. * otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
  34. * 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
  35. * 真实表集合里只有staff_man和staff_woman;
  36. *
  37. * @param shardingValues
  38. * 分片键的值。
  39. * 如:本人此次示例中,要路由到那个数据库源,是由age为数据源分片键的,age的列类型为int,
  40. * 所以这里的泛型是Integer。
  41. * 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
  42. * 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
  43. * 注: ComplexKeysShardingAlgorithm算法,ShardingValue接口的实现是ListShardingValue。
  44. * 本人这里,shardingValues的toString形如
  45. * shardingValues:[
  46. * ListShardingValue(logicTableName=staff, columnName=age, values=[21]),
  47. * ListShardingValue(logicTableName=staff, columnName=gender, values=[女])
  48. * ]
  49. *
  50. * @return 路由后的SQL要使用的数据源(库)名字的集合 或 路由后的SQL要使用的真实表名字的集合
  51. */
  52. @Override
  53. public Collection<String> doSharding(Collection<String> availableTargetNames,
  54. Collection<ShardingValue> shardingValues) {
  55. List<String> list = new ArrayList<>(4);
  56. ListShardingValue listShardingValue;
  57. for (ShardingValue item : shardingValues) {
  58. // 将item拆箱转换为listShardingValue
  59. listShardingValue = (ListShardingValue)item;
  60. System.out.println("逻辑表:" + listShardingValue.getLogicTableName());
  61. System.out.println("列名:" + listShardingValue.getColumnName());
  62. System.out.println("改列的值:" + listShardingValue.getValues());
  63. }
  64. return list;
  65. }
  66. }

StaffTableTableShardingAlgorithm:

  1. import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
  2. import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
  3. import java.util.Collection;
  4. /**
  5. * 表分片策略
  6. *
  7. * 提示:PreciseShardingAlgorithm接口的泛型,视对应分片键的数据类型而定
  8. * 如:列是字符串,那么这里是 String
  9. * 列是int,那么这里是 Integer
  10. * 列是bigint,那么这里是 Long
  11. *
  12. * @author JustryDeng
  13. * @date 2019/5/31 10:11
  14. */
  15. public class StaffTableTableShardingAlgorithm implements PreciseShardingAlgorithm<String> {
  16. /**
  17. * Sharding.
  18. *
  19. * @param availableTargetNames
  20. * 数据源(库)名称集合 或 真实表名称集合。
  21. *
  22. * 提示:数据库源一旦定下来了,那么对应有哪些可用的真实表也就随之定下来了。
  23. *
  24. * 注:这里为: 数据源(库)名称集合。
  25. * 如,本人此次示例中,设置了的数据源有otherDb、youngerDb、olderDb,
  26. * 那么availableTargetNames输出就应为[otherDb, youngerDb, olderDb]
  27. *
  28. * 注:因为是先路由定位库,再路由定位真实表;所以一旦库定下来了,那么真实表的集合就定下来了。
  29. * 以本人的此项目的库与表进行说明:
  30. * otherDb库只有表staff.
  31. * youngerDb库有表staff_man。staff_woman.
  32. * olderDb库有表staff_man。staff_woman.
  33. * 在进行表分片之前会先进性数据库(数据源)分片,在数据源分片时,就路由定下来了走
  34. * otherDb的话,那么这里定位真实表时,候选的真实表集合里只有staff;如果
  35. * 在数据源分片时,路由定下来了走youngerDb的话,那么这里定位真实表时,候选的
  36. * 真实表集合里只有staff_man和staff_woman;
  37. *
  38. * @param shardingValue
  39. * 分片键的值。
  40. * 如:本人此次示例中,路由至哪张表,是由gender为真实表分片键的,
  41. * gender的列类型为char,所以这里的泛型是String。
  42. * 如果分片键的类型是int的话,这里的泛型就应该是Integer.
  43. * 如果分片键的类型是bigint的话,这里的泛型就应该是Long.
  44. * 如果分片键的类型是varchar/char的话,这里的泛型就应该是String.
  45. *
  46. * @return 路由后的SQL要使用的数据源(库)的名字 或 路由后的SQL要使用的真实表的名字
  47. * 注:这里为 路由后的SQL要使用的真实表的名字
  48. */
  49. @Override
  50. public String doSharding(Collection<String> availableTargetNames,
  51. PreciseShardingValue<String> shardingValue) {
  52. // 根据本人的真实数据节点信息, 如果 可用表里面包含staff,说明一定用的是otherDb数据源,
  53. // 而该数据库里面只有一张表staff, 这里直接返回即可
  54. if (availableTargetNames.contains("staff")) {
  55. return "staff";
  56. }
  57. // 如果是youngerDb数据源 或 olderDb数据源 的话,会走到下面的逻辑
  58. String tmpGender = shardingValue.getValue();
  59. if ("男".equals(tmpGender)) {
  60. return "staff_man";
  61. } else if ("女".equals(tmpGender)) {
  62. return "staff_woman";
  63. }
  64. throw new UnsupportedOperationException();
  65. }
  66. }

测试一下

测试准备:正常编写针对逻辑表的相关类以及SQL语句

StaffPO模型:

  1. import lombok.AllArgsConstructor;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. /**
  6. * 职工模型, 对应staff表
  7. *
  8. * @author JustryDeng
  9. * @date 2019/6/3 23:26
  10. */
  11. @Data
  12. @Builder
  13. @NoArgsConstructor
  14. @AllArgsConstructor
  15. public class StaffPO {
  16. /** 分布式主键id */
  17. private String id;
  18. /** 年龄 */
  19. private Integer age;
  20. /** 姓名 */
  21. private String name;
  22. /** 性别 */
  23. private String gender;
  24. }

ShardingDatabaseTableApplication启动类:

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  4. import org.springframework.transaction.annotation.EnableTransactionManagement;
  5. /**
  6. * 启动类
  7. *
  8. * @author JustryDeng
  9. * @date 2019/5/29 11:03
  10. */
  11. @SpringBootApplication
  12. @EnableTransactionManagement
  13. public class ShardingDatabaseTableApplication {
  14. public static void main(String[] args) {
  15. SpringApplication.run(ShardingDatabaseTableApplication.class, args);
  16. }
  17. }

ShardingService业务接口:

  1. import com.aspire.shardingdatabasetable.model.StaffPO;
  2. import java.util.List;
  3. /**
  4. * Service层
  5. *
  6. * @author JustryDeng
  7. * @date 2019/5/29 17:35
  8. */
  9. public interface ShardingService {
  10. /**
  11. * 插入测试
  12. *
  13. * @param staffPO
  14. * 职工模型
  15. * @return 受影响行数
  16. * @date 2019/6/3 23:42
  17. */
  18. int insertDemo(StaffPO staffPO);
  19. /**
  20. * 查询测试
  21. *
  22. * @param age
  23. * 年龄条件
  24. * @return 满足要求的职工信息集合
  25. * @date 2019/6/4 21:55
  26. */
  27. List<StaffPO> queryDemo(Integer age);
  28. }

ShardingServiceImpl业务实现:

  1. import com.aspire.shardingdatabasetable.mapper.ShardingMapper;
  2. import com.aspire.shardingdatabasetable.model.StaffPO;
  3. import com.aspire.shardingdatabasetable.service.ShardingService;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.transaction.annotation.Transactional;
  7. import java.util.List;
  8. /**
  9. * 业务逻辑层
  10. *
  11. * @author JustryDeng
  12. * @date 2019/5/29 17:35
  13. */
  14. @Slf4j
  15. @Service
  16. public class ShardingServiceImpl implements ShardingService {
  17. private final ShardingMapper shardingMapper;
  18. public ShardingServiceImpl(ShardingMapper shardingMapper) {
  19. this.shardingMapper = shardingMapper;
  20. }
  21. @Override
  22. @Transactional(rollbackFor = {Exception.class})
  23. public int insertDemo(StaffPO staffPO) {
  24. log.info("got into ShardingServiceImpl -> insertDemo, param is -> {}", staffPO);
  25. return shardingMapper.insertData(staffPO);
  26. }
  27. @Override
  28. public List<StaffPO> queryDemo(Integer age) {
  29. log.info("got into ShardingServiceImpl -> queryDemo, param is -> {}", age);
  30. return shardingMapper.queryStaffByAge(age);
  31. }
  32. }

ShardingMapper数据操作层:

  1. import com.aspire.shardingdatabasetable.model.StaffPO;
  2. import org.apache.ibatis.annotations.Insert;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.apache.ibatis.annotations.Select;
  6. import java.util.List;
  7. /**
  8. * 持久层
  9. *
  10. * @author JustryDeng
  11. * @date 2019/5/29 17:36
  12. */
  13. @Mapper
  14. public interface ShardingMapper {
  15. /**
  16. * 向逻辑表staff中插入数据
  17. *
  18. * @param staffPO
  19. * 职工模型
  20. * @return 受影响行数
  21. * @date 2019/6/3 23:38
  22. */
  23. @Insert({"insert into staff (`id`, `age`, `name`, `gender`) values (#{staffPO.id},",
  24. " #{staffPO.age}, #{staffPO.name}, #{staffPO.gender})"})
  25. int insertData(@Param("staffPO") StaffPO staffPO);
  26. /**
  27. * 根据年龄大于等于给定age的职工信息
  28. *
  29. * @param age
  30. * 年龄条件
  31. * @return 符合要求的职工集合
  32. * @date 2019/6/4 21:52
  33. */
  34. @Select("select id, name, age, gender from staff where age >= #{age}")
  35. List<StaffPO> queryStaffByAge(Integer age);
  36. }

编写测试方法

  1. import com.aspire.shardingdatabasetable.model.StaffPO;
  2. import com.aspire.shardingdatabasetable.service.ShardingService;
  3. import org.junit.Assert;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.test.context.junit4.SpringRunner;
  9. import java.util.List;
  10. import java.util.UUID;
  11. @RunWith(SpringRunner.class)
  12. @SpringBootTest
  13. public class ShardingDatabaseTableApplicationTests {
  14. @Autowired
  15. ShardingService shardingService;
  16. @Test
  17. public void allTest() {
  18. oneTest();
  19. twoTest();
  20. threeTest();
  21. fourTest();
  22. fiveTest();
  23. sixTest();
  24. }
  25. @Test
  26. public void oneTest() {
  27. String uuid = UUID.randomUUID().toString();
  28. StaffPO staffPO = StaffPO.builder()
  29. .id(uuid)
  30. .name("邓沙利文")
  31. .age(25)
  32. .gender("男")
  33. .build();
  34. int result = shardingService.insertDemo(staffPO);
  35. Assert.assertEquals(1, result);
  36. }
  37. @Test
  38. public void twoTest() {
  39. String uuid = UUID.randomUUID().toString();
  40. StaffPO staffPO = StaffPO.builder()
  41. .id(uuid)
  42. .name("疯一般的女子")
  43. .age(123)
  44. .gender("女")
  45. .build();
  46. int result = shardingService.insertDemo(staffPO);
  47. Assert.assertEquals(1, result);
  48. }
  49. @Test
  50. public void threeTest() {
  51. String uuid = UUID.randomUUID().toString();
  52. StaffPO staffPO = StaffPO.builder()
  53. .id(uuid)
  54. .name("无敌小婷妹")
  55. .age(21)
  56. .gender("女")
  57. .build();
  58. int result = shardingService.insertDemo(staffPO);
  59. Assert.assertEquals(1, result);
  60. }
  61. @Test
  62. public void fourTest() {
  63. String uuid = UUID.randomUUID().toString();
  64. StaffPO staffPO = StaffPO.builder()
  65. .id(uuid)
  66. .name("邓~")
  67. .age(125)
  68. .gender("男")
  69. .build();
  70. int result = shardingService.insertDemo(staffPO);
  71. Assert.assertEquals(1, result);
  72. }
  73. @Test
  74. public void fiveTest() {
  75. String uuid = UUID.randomUUID().toString();
  76. StaffPO staffPO = StaffPO.builder()
  77. .id(uuid)
  78. .name("亨得帅")
  79. .age(66)
  80. .gender("男")
  81. .build();
  82. int result = shardingService.insertDemo(staffPO);
  83. Assert.assertEquals(1, result);
  84. }
  85. @Test
  86. public void sixTest() {
  87. String uuid = UUID.randomUUID().toString();
  88. StaffPO staffPO = StaffPO.builder()
  89. .id(uuid)
  90. .name("小聋女")
  91. .age(80)
  92. .gender("女")
  93. .build();
  94. int result = shardingService.insertDemo(staffPO);
  95. Assert.assertEquals(1, result);
  96. }
  97. @Test
  98. public void qeuryTest() {
  99. List<StaffPO> result = shardingService.queryDemo(10);
  100. for (StaffPO staffPO : result) {
  101. System.out.println(staffPO);
  102. }
  103. }
  104. }

进行测试

插入测试:运行allTest方法后,控制台输出:

  1. . ____ _ __ _ _
  2. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
  3. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
  4. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
  5. ' |____| .__|_| |_|_| |_\__, | / / / /
  6. =========|_|==============|___/=/_/_/_/
  7. :: Spring Boot :: (v2.1.4.RELEASE)
  8. 23:56:49.904 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  9. 23:56:49.906 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  10. 23:56:49.906 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: youngerDb ::: insert into staff_man (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [2c757252-3779-4d0f-b70f-db272f12b091, 25, 邓沙利文, 男]
  11. 23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  12. 23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  13. 23:56:50.116 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: otherDb ::: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [5a6ed073-5891-482f-ba1e-959f4e832cfd, 123, 疯一般的女子, 女]
  14. 23:56:50.149 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  15. 23:56:50.150 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  16. 23:56:50.150 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: youngerDb ::: insert into staff_woman (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [3d0aadf3-94e2-4ee8-9715-421fd8f4bc9d, 21, 无敌小婷妹, 女]
  17. 23:56:50.208 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  18. 23:56:50.209 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  19. 23:56:50.209 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: otherDb ::: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [c1cde34f-3093-4296-ac57-bef30f7b4777, 125, 邓~, 男]
  20. 23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  21. 23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  22. 23:56:50.302 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: olderDb ::: insert into staff_man (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [29c8165f-ba9f-4aad-bb27-552026840ca4, 66, 亨得帅, 男]
  23. 23:56:50.374 [main] INFO Sharding-JDBC-SQL:59- Logic SQL: insert into staff (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?)
  24. 23:56:50.375 [main] INFO Sharding-JDBC-SQL:59- SQLStatement: InsertStatement(columns=[Column(name=id, tableName=staff), Column(name=age, tableName=staff), Column(name=name, tableName=staff), Column(name=gender, tableName=staff)], multipleConditions=[], columnsListLastPosition=48, generateKeyColumnIndex=-1, afterValuesPosition=57, valuesListLastPosition=69, generatedKey=null)
  25. 23:56:50.375 [main] INFO Sharding-JDBC-SQL:59- Actual SQL: olderDb ::: insert into staff_woman (`id`, `age`, `name`, `gender`) values (?, ?, ?, ?) ::: [3f0463a8-26bc-4cf2-8133-7878fda556e0, 80, 小聋女, 女]

打开库表,观察:

older库staff_man表:

older库staff_woman表:

younger库staff_man表:

younger库staff_woman表:

other库staff表:

可见分库分表成功!

查询测试:运行qeuryTest方法后,控制台输出:

查询也没问题!

ShardingSphere实现分库分表完毕!

 

^_^ 如有不当之处,欢迎指正

^_^ 参考链接
              
https://shardingsphere.apache.org/d...
              http://wuwenliang.net/2019/03/26/...
              https://www.cnblogs.com/mr-yang-localhost/p/8313360.html

^_^ 测试代码托管链接
              
https://github.com/JustryDeng/CommonRepository

^_^ 本文已经被收录进《程序员成长笔记(五)》,笔者JustryDeng

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/757095
推荐阅读
相关标签
  

闽ICP备14008679号