分库分表中间件Sharding-JDBC详解

ゞ 浴缸里的玫瑰 2022-09-07 09:13 253阅读 0赞

分库分表中间件Sharding-JDBC详解

    1. 分库分表概述
    • 1.1 为什么需要分库分表
    • 1.2 分库分表的方式
      • 1.2.1.垂直分表
      • 1.2.2.垂直分库
      • 1.2.3.水平分库
      • 1.2.4.水平分表
    • 1.3 分库分表问题分析
      • 1.3.1 事务一致性问题
      • 1.3.2 跨节点关联查询
      • 1.3.3 跨节点分页、排序函数
      • 1.3.4 主键避重
      • 1.3.5 公共表
    1. Sharding-JDBC详解
    • 2.1 Sharding-JDBC简介
    • 2.2 Sharding-JDBC性能对比
    • 2.3 Sharding-JDBC原理分析
    1. 实现验证
    • 3.1 环境准备
      • 3.1.1 环境说明
      • 3.1.2 创建数据库
    • 3.2 代码实现
      • 3.2.1 pom.xml
      • 3.2.2 application.properties
      • 3.2.3 SwaggerConfig
      • 3.2.4 Order
      • 3.2.5 OrderMapper
      • 3.2.6 OrderService
      • 3.2.7 OrderServiceImpl
      • 3.2.8 OrderController
      • 3.2.8 ShardingSimpleApplication
    • 3.3 数据验证

1. 分库分表概述

1.1 为什么需要分库分表

随着公司业务快速发展,数据库中的数据量增大,访问性能也变慢了,虽然通过机器集群,sql优化,性能调优等方式在一定程度上可以起到提高性能的作用,但是并不能从根本上解决单库,单表数据量过大的问题。

分库分表就是为了解决由于数据量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干数据库组成,将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。

1.2 分库分表的方式

分库分表按方式有两种:垂直拆分和水平拆分。
垂直切分拆的是表结构,水平拆分拆的是数据。

分库分表按类型包括分库和分表两个部分,在生产中通常包括:垂直分库、水平分库、垂直分表、水平分表四种方式。

归根结底分库要解决的是硬件资源的问题,不管是拆分字段,还是拆分数据,都是要拆到不同的数据库不同的服务器上,从硬件资源上解决性能瓶颈。而分表是解决单表数据量过大的问题,拆分完后还是放在同一数据库中不同表里面,只是减少了单表的读写锁资源消耗,如果性能瓶颈在硬件资源,只是简单的分表并不能从根本上解决问题,所有具体分库分表亦或者是结合使用都要结合具体的业务场景,一切撇开实际业务场景谈需求都是耍流氓。

1.2.1.垂直分表

垂直分表定义:将一个表按照字段分成多表,每个表存储其中一部分字段。

它带来的提升是:
1.为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览互不影响。
2.充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率所拖累。

一般来说,某业务实体中的各个数据项的访问频次是不一样的,部分数据项可能是占用存储空间比较大的BLOB或是TEXT。例如上例中的商品描述。所以,当表数据量很大时,可以将表按字段切开,将热门字段、冷门字段分开放置在不同库中,这些库可以放在不同的存储设备上,避免IO争抢。垂直切分带来的性能提升主要集中在热门数据的操作效率上,而且磁盘争用情况减少。

通常我们按以下原则进行垂直拆分:

  1. 把不常用的字段单独放在一张表;
  2. 把text,blob等大字段拆分出来放在附表中;
  3. 经常组合查询的列放在一张表中

1.2.2.垂直分库

垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。

它带来的提升是:
解决业务层面的耦合,业务清晰能对不同业务的数据进行分级管理、维护、监控、扩展等高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。

1.2.3.水平分库

水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

它带来的提升是:
解决了单库大数据,高并发的性能瓶颈。提高了系统的稳定性及可用性。当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平分库了,经过水平切分的优化,往往能解决单库存储量及性能瓶颈。但由于同一个表被分配在不同的数据库,需要额外进行数据操作的路由工作,因此大大提升了系统复杂度。

1.2.4.水平分表

水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。

它带来的提升是:
优化单一表数据量过大而产生的性能问题避免IO争抢并减少锁表的几率库内的水平分表,解决了单一表数据量过大的问题,分出来的小表中只包含一部分数据,从而使得单个表的数据量变小,提高检索性能。

1.3 分库分表问题分析

1.3.1 事务一致性问题

由于分库分表把数据分布在不同库甚至不同服务器,不可避免会带来分布式事务问题。

1.3.2 跨节点关联查询

由于原来一张表的数据现在分布在不同数据库,不同表中,在涉及到多表关联,一定要设计好分片策略以及查询条件,否则很可能出现笛卡尔积现象,导致性能更低。

1.3.3 跨节点分页、排序函数

跨节点多库进行查询时,limit分页、order by排序等问题,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序。

1.3.4 主键避重

不能在采用数据库自增主键,应采用分布式id,保证全局唯一。

1.3.5 公共表

实际的应用场景中,参数表、数据字典表等都是数据量较小,变动少,而且属于高频联合查询的依赖表。例子中地理区域表也属于此类型。可以将这类表在每个数据库都保存一份,所有对公共表的更新操作都同时发送到所有分库执行。

2. Sharding-JDBC详解

2.1 Sharding-JDBC简介

Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的数据水平扩展、分布式事务和分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

Apache ShardingSphere 5.x 版本开始致力于可插拔架构,项目的功能组件能够灵活的以可插拔的方式进行扩展。 目前,数据分片、读写分离、数据加密、影子库压测等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 与协议的支持,均通过插件的方式织入项目。 开发者能够像使用积木一样定制属于自己的独特系统。Apache ShardingSphere 目前已提供数十个 SPI 作为系统的扩展点,仍在不断增加中。

ShardingSphere 已于2020年4月16日成为 Apache 软件基金会的顶级项目。

定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 标准的数据库。

官方地址:https://shardingsphere.apache.org/index_zh.html

sharding-jdbc官网文档:https://shardingsphere.apache.org/document/current/cn/overview/#shardingsphere-jdbc

在这里插入图片描述在这里插入图片描述

2.2 Sharding-JDBC性能对比

1.性能损耗测试:服务器资源充足、并发数相同,比较JDBC和Sharding-JDBC性能损耗,Sharding-JDBC相对JDBC损耗不超过7%。
2.性能对比测试:服务器资源使用到极限,相同的场景JDBC与Sharding-JDBC的吞吐量相当。

  1. 性能对比测试:服务器资源使用到极限,Sharding-JDBC采用分库分表后,Sharding-JDBC吞吐量较JDBC不分表有接近2倍的提升。

2.3 Sharding-JDBC原理分析

执行流程: SQL解析 => 查询优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并

3. 实现验证

人工创建两张表,t_order_1和t_order_2,这两张表是订单表拆分后的表,通过Sharding-Jdbc向订单表插入数据,按照一定的分片规则,主键为偶数的进入t_order_1,另一部分数据进入t_order_2,通过Sharding-Jdbc 查询数据,根据 SQL语句的内容从t_order_1或t_order_2查询数据。

3.1 环境准备

3.1.1 环境说明

操作系统:Win10
数据库:MySQL-5.7.25
JDK:64位 jdk1.8.0_201
应用框架:spring-boot-2.1.3.RELEASE,Mybatis3.5.0
Sharding-JDBC:sharding-jdbc-spring-boot-starter-4.0.0-RC1

3.1.2 创建数据库

创建订单库order_db_1,order_db_2
在order_db_1yuorder_db_2中分别创建t_order_1、t_order_2表

  1. -- 创建订单库order_db
  2. CREATE DATABASE `order_db_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
  3. CREATE DATABASE `order_db_2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
  4. -- order_db中创建t_order_1t_order_2表,这个要在两个库分别创建
  5. DROP TABLE IF EXISTS `t_order_1`;
  6. CREATE TABLE `t_order_1` (
  7. `order_id` bigint(20) NOT NULL COMMENT '订单id',
  8. `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
  9. `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  10. `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
  11. PRIMARY KEY (`order_id`) USING BTREE
  12. ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  13. DROP TABLE IF EXISTS `t_order_2`;
  14. CREATE TABLE `t_order_2` (
  15. `order_id` bigint(20) NOT NULL COMMENT '订单id',
  16. `price` decimal(10, 2) NOT NULL COMMENT '订单价格',
  17. `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  18. `status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
  19. PRIMARY KEY (`order_id`) USING BTREE
  20. ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

3.2 代码实现

3.2.1 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" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-starter-parent</artifactId>
  7. <version>2.5.4</version>
  8. <relativePath/> <!-- lookup parent from repository -->
  9. </parent>
  10. <groupId>com.zrj.sharding</groupId>
  11. <artifactId>sharding-simple</artifactId>
  12. <version>0.0.1-SNAPSHOT</version>
  13. <name>sharding-simple</name>
  14. <description>Demo project for Spring Boot</description>
  15. <properties>
  16. <java.version>1.8</java.version>
  17. </properties>
  18. <dependencies>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-web</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-test</artifactId>
  26. <scope>test</scope>
  27. </dependency>
  28. <!--swagger2依赖-->
  29. <dependency>
  30. <groupId>io.springfox</groupId>
  31. <artifactId>springfox-swagger2</artifactId>
  32. <version>2.9.2</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>io.springfox</groupId>
  36. <artifactId>springfox-swagger-ui</artifactId>
  37. <version>2.9.2</version>
  38. </dependency>
  39. <!--sharding-jdbc-->
  40. <dependency>
  41. <groupId>org.projectlombok</groupId>
  42. <artifactId>lombok</artifactId>
  43. <version>1.18.0</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>javax.interceptor</groupId>
  47. <artifactId>javax.interceptor-api</artifactId>
  48. <version>1.2</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>mysql</groupId>
  52. <artifactId>mysql-connector-java</artifactId>
  53. <version>5.1.47</version>
  54. </dependency>
  55. <dependency>
  56. <groupId>org.mybatis.spring.boot</groupId>
  57. <artifactId>mybatis-spring-boot-starter</artifactId>
  58. <version>2.0.0</version>
  59. </dependency>
  60. <dependency>
  61. <groupId>com.alibaba</groupId>
  62. <artifactId>druid-spring-boot-starter</artifactId>
  63. <version>1.1.16</version>
  64. </dependency>
  65. <dependency>
  66. <groupId>org.apache.shardingsphere</groupId>
  67. <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  68. <version>4.0.0-RC1</version>
  69. </dependency>
  70. <dependency>
  71. <groupId>com.baomidou</groupId>
  72. <artifactId>mybatis-plus-boot-starter</artifactId>
  73. <version>3.1.0</version>
  74. </dependency>
  75. <dependency>
  76. <groupId>com.baomidou</groupId>
  77. <artifactId>mybatis-plus-generator</artifactId>
  78. <version>3.1.0</version>
  79. </dependency>
  80. <dependency>
  81. <groupId>org.mybatis</groupId>
  82. <artifactId>mybatis-typehandlers-jsr310</artifactId>
  83. <version>1.0.2</version>
  84. </dependency>
  85. </dependencies>
  86. <build>
  87. <plugins>
  88. <plugin>
  89. <groupId>org.springframework.boot</groupId>
  90. <artifactId>spring-boot-maven-plugin</artifactId>
  91. </plugin>
  92. </plugins>
  93. </build>
  94. </project>

3.2.2 application.properties

  1. server.port=8080
  2. spring.application.name = sharding-jdbc-simple-demo
  3. server.servlet.context-path = /sharding-jdbc-simple-demo
  4. server.servlet.encoding.enabled = true
  5. server.servlet.encoding.charset = UTF-8
  6. server.servlet.encoding.force = true
  7. spring.main.allow-bean-definition-overriding = true
  8. # mybatis驼峰映射
  9. mybatis.configuration.map-underscore-to-camel-case = true
  10. #sharding-jdbc分片规则配置
  11. #数据源
  12. spring.shardingsphere.datasource.names = m0,m1,m2
  13. spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
  14. spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
  15. spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
  16. spring.shardingsphere.datasource.m1.username = root
  17. spring.shardingsphere.datasource.m1.password = 123456
  18. spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
  19. spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
  20. spring.shardingsphere.datasource.m2.url = jdbc:mysql://localhost:3306/order_db_2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
  21. spring.shardingsphere.datasource.m2.username = root
  22. spring.shardingsphere.datasource.m2.password = 123456
  23. spring.shardingsphere.datasource.m0.type = com.alibaba.druid.pool.DruidDataSource
  24. spring.shardingsphere.datasource.m0.driver-class-name = com.mysql.jdbc.Driver
  25. spring.shardingsphere.datasource.m0.url = jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
  26. spring.shardingsphere.datasource.m0.username = root
  27. spring.shardingsphere.datasource.m0.password = 123456
  28. # 主库从库逻辑数据源定义 ds0为user_db
  29. #spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0
  30. #spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s0
  31. # 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
  32. spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
  33. spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}
  34. # 指定t_order表的数据分布情况,配置数据节点 m1.t_order_1,m1.t_order_2,m2.t_order_1,m2.t_order_2
  35. spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}
  36. #spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = m$->{0}.t_user
  37. #spring.shardingsphere.sharding.tables.t_user.actual‐data‐nodes = m$‐>{0}.t_user
  38. spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = m0.t_user
  39. # 指定t_order表的主键生成策略为SNOWFLAKE
  40. spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
  41. spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
  42. # 指定t_order表的分片策略,分片策略包括分片键和分片算法
  43. spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
  44. spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}
  45. spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column = user_id
  46. spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression = t_user
  47. # 打开sql输出日志
  48. spring.shardingsphere.props.sql.show = true
  49. swagger.enable = true
  50. logging.level.root = info
  51. logging.level.org.springframework.web = info
  52. logging.level.com.zrj.sharding = debug
  53. logging.level.druid.sql = debug

3.2.3 SwaggerConfig

  1. package com.zrj.sharding.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.PathSelectors;
  6. import springfox.documentation.builders.RequestHandlerSelectors;
  7. import springfox.documentation.service.ApiInfo;
  8. import springfox.documentation.service.Contact;
  9. import springfox.documentation.spi.DocumentationType;
  10. import springfox.documentation.spring.web.plugins.Docket;
  11. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  12. /** * Swagger2配置 * * @author zrj * @since 2021/8/22 **/
  13. @Configuration
  14. @EnableSwagger2
  15. public class SwaggerConfig {
  16. /** * swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等 */
  17. @Bean
  18. public Docket createRestApi() {
  19. return new Docket(DocumentationType.SWAGGER_2)
  20. .apiInfo(apiInfo())
  21. .select()
  22. // 为当前包路径
  23. .apis(RequestHandlerSelectors.basePackage("com.zrj.sharding.controller")).paths(PathSelectors.any())
  24. .build();
  25. }
  26. /** * 构建 api文档的详细信息函数,注意这里的注解引用的是哪个 */
  27. private ApiInfo apiInfo() {
  28. return new ApiInfoBuilder()
  29. // 页面标题
  30. .title("分库分表管理")
  31. // 创建人信息
  32. .contact(new Contact("shardingsphere", "https://shardingsphere.apache.org/index_zh.html", ""))
  33. // 版本号
  34. .version("V1.0")
  35. // 描述
  36. .description("sharding-jdbc")
  37. .build();
  38. }
  39. }

3.2.4 Order

  1. package com.zrj.sharding.entity;
  2. import java.io.Serializable;
  3. /** * (TOrder)实体类 * * @author zrj * @since 2021/8/22 */
  4. public class Order implements Serializable {
  5. private static final long serialVersionUID = 849675519182821942L;
  6. /** * 订单id */
  7. private Long orderId;
  8. /** * 订单价格 */
  9. private Double price;
  10. /** * 下单用户id */
  11. private Long userId;
  12. /** * 订单状态 */
  13. private String status;
  14. public Long getOrderId() {
  15. return orderId;
  16. }
  17. public void setOrderId(Long orderId) {
  18. this.orderId = orderId;
  19. }
  20. public Double getPrice() {
  21. return price;
  22. }
  23. public void setPrice(Double price) {
  24. this.price = price;
  25. }
  26. public Long getUserId() {
  27. return userId;
  28. }
  29. public void setUserId(Long userId) {
  30. this.userId = userId;
  31. }
  32. public String getStatus() {
  33. return status;
  34. }
  35. public void setStatus(String status) {
  36. this.status = status;
  37. }
  38. @Override
  39. public String toString() {
  40. return "TOrder {" +
  41. "orderId : " + orderId + ", " +
  42. "price : " + price + ", " +
  43. "userId : " + userId + ", " +
  44. "status : " + status + ", " +
  45. '}';
  46. }
  47. }

Response

  1. package com.zrj.sharding.entity;
  2. import lombok.Data;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Component;
  5. /** * 统一结果集 * * @author zrj * @since 2021/8/22 **/
  6. @Data
  7. @Component
  8. public class Response<T> {
  9. public static ResponseCode responseCode;
  10. /** * 提示消息 */
  11. public String message;
  12. /** * 具体返回的数据 */
  13. public T data;
  14. /** * 状态码 */
  15. public String code;
  16. public Response(String code, String message, T data) {
  17. this.message = message;
  18. this.code = code;
  19. this.data = data;
  20. }
  21. public Response(String code, String msg) {
  22. this.message = msg;
  23. this.code = code;
  24. }
  25. @Autowired
  26. public Response(ResponseCode responseCode) {
  27. Response.responseCode = responseCode;
  28. }
  29. /** * 返回成功Response对象 */
  30. public static <T> Response<T> success(String successMessage, T data) {
  31. return new Response<>(responseCode.getSuccessCode(), successMessage, data);
  32. }
  33. /** * 返回错误Response对象 */
  34. public static <T> Response<T> fail(String errorMessage) {
  35. return new Response<>(responseCode.getErrorCode(), errorMessage);
  36. }
  37. }
  38. @Data
  39. @Component
  40. public class ResponseCode {
  41. public String successCode = "200";
  42. public String errorCode = "500";
  43. public String authErrorCode = "300";
  44. }

3.2.5 OrderMapper

  1. package com.zrj.sharding.mapper;
  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 org.springframework.stereotype.Component;
  7. import java.math.BigDecimal;
  8. import java.util.List;
  9. import java.util.Map;
  10. /** * 订单Mapper接口 * * @author zrj * @since 2021/8/22 **/
  11. @Mapper
  12. @Component
  13. public interface OrderMapper {
  14. /** * 新增订单 * * @param price 订单价格 * @param userId 用户id * @param status 订单状态 * @return */
  15. @Insert("insert into t_order(price,user_id,status) value(#{price},#{userId},#{status})")
  16. int insertOrder(@Param("price") Double price, @Param("userId") Long userId,
  17. @Param("status") String status);
  18. /** * 根据id列表查询多个订单 * * @param orderIds 订单id列表 * @return */
  19. @Select({ "<script>" +
  20. "select " +
  21. " * " +
  22. " from t_order t" +
  23. " where t.order_id in " +
  24. "<foreach collection='orderIds' item='id' open='(' separator=',' close=')'>" +
  25. " #{id} " +
  26. "</foreach>" +
  27. "</script>"})
  28. List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
  29. }

3.2.6 OrderService

  1. package com.zrj.sharding.service;
  2. import com.zrj.sharding.entity.Order;
  3. import java.util.List;
  4. import java.util.Map;
  5. /** * 订单接口 * * @author zrj * @since 2021/8/22 */
  6. public interface OrderService {
  7. /** * 新增订单 */
  8. int insertOrder(Order order);
  9. /** * 根据id列表查询多个订单 */
  10. List<Map> selectOrderbyIds(List<Long> orderIds);
  11. }

3.2.7 OrderServiceImpl

  1. package com.zrj.sharding.service.impl;
  2. import com.zrj.sharding.entity.Order;
  3. import com.zrj.sharding.mapper.OrderMapper;
  4. import com.zrj.sharding.service.OrderService;
  5. import org.springframework.stereotype.Service;
  6. import javax.annotation.Resource;
  7. import java.math.BigDecimal;
  8. import java.util.List;
  9. import java.util.Map;
  10. /** * 订单实现类 * * @author zrj * @since 2021/8/22 */
  11. @Service("OrderService")
  12. public class OrderServiceImpl implements OrderService {
  13. @Resource
  14. private OrderMapper orderMapper;
  15. @Override
  16. public int insertOrder(Order order) {
  17. return orderMapper.insertOrder(order.getPrice(), order.getUserId(), order.getStatus());
  18. }
  19. @Override
  20. public List<Map> selectOrderbyIds(List<Long> orderIds) {
  21. return orderMapper.selectOrderbyIds(orderIds);
  22. }
  23. }

3.2.8 OrderController

  1. package com.zrj.sharding.controller;
  2. import com.zrj.sharding.entity.Order;
  3. import com.zrj.sharding.entity.Response;
  4. import com.zrj.sharding.service.OrderService;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. import org.springframework.web.bind.annotation.*;
  8. import javax.annotation.Resource;
  9. import java.util.List;
  10. import java.util.Map;
  11. /** * 订单管理 * 采用分库分表中间件ShardingJdbc * * @author zrj * @since 2021/8/22 */
  12. @RestController
  13. @RequestMapping("/order")
  14. @Api(tags = "订单管理", description = "分库分表")
  15. public class OrderController {
  16. @Resource
  17. private OrderService orderService;
  18. /** * 测试服务 */
  19. @GetMapping("/test")
  20. @ApiOperation(value = "测试服务", notes = "测试方法的备注说明", httpMethod = "GET")
  21. public Response test() {
  22. return Response.success("查询成功", null);
  23. }
  24. /** * 新增订单 */
  25. @ApiOperation(value = "新增订单", httpMethod = "POST")
  26. @RequestMapping(value = "insert", method = RequestMethod.POST)
  27. public Response<Integer> insert(@RequestBody Order order) {
  28. int result = orderService.insertOrder(order);
  29. if (result > 0) {
  30. return Response.success("新增成功", result);
  31. }
  32. return Response.fail("新增失败");
  33. }
  34. /** * 根据ids查询订单 */
  35. @ApiOperation(value = "查询订单", httpMethod = "POST")
  36. @RequestMapping(value = "selectOrderbyIds", method = RequestMethod.POST)
  37. public Response<List> selectOrderbyIds(@RequestBody List<Long> orderIds) {
  38. List<Map> result = orderService.selectOrderbyIds(orderIds);
  39. if (result != null) {
  40. return Response.success("查询成功", result);
  41. }
  42. return Response.fail("查询失败");
  43. }
  44. }

3.2.8 ShardingSimpleApplication

  1. package com.zrj.sharding;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. /** * 订单服务 * * @author zrj * @since 2021/8/22 */
  6. @SpringBootApplication
  7. @MapperScan("com.zrj.sharding.mapper")
  8. public class ShardingSimpleApplication {
  9. public static void main(String[] args) {
  10. SpringApplication.run(ShardingSimpleApplication.class, args);
  11. }
  12. }

3.3 数据验证

根据分片策略,根据逻辑表根据策略新增到不同数据库不同表里面,查询也是都能成功。
在这里插入图片描述在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,253人围观)

还没有评论,来说两句吧...

相关阅读

    相关 数据库分库

    【编者按】数据库分库分表从互联网时代开启至今,一直是热门话题。在NoSQL横行的今天,关系型数据库凭借其稳定、查询灵活、兼容等特性,仍被大多数公司作为首选数据库。因此,合理采用

    相关 解读分库Sharding-JDBC

    【编者按】数据库分库分表从互联网时代开启至今,一直是热门话题。在NoSQL横行的今天,关系型数据库凭借其稳定、查询灵活、兼容等特性,仍被大多数公司作为首选数据库。因此,合理采用

    相关 解读分库Sharding-JDBC

    【编者按】数据库分库分表从互联网时代开启至今,一直是热门话题。在NoSQL横行的今天,关系型数据库凭借其稳定、查询灵活、兼容等特性,仍被大多数公司作为首选数据库。因此,合理采用