springboot 按月分表的实现方式

下面是springboot按月分表的实现方式完整攻略:

第一步:创建表和初始化数据

首先,我们需要创建一张原始的订单表,结构如下:

CREATE TABLE `order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
  `order_amount` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

接下来,初始化一些数据,可以通过以下SQL语句插入数据:

INSERT INTO `order`(order_no, order_amount, create_time) VALUES 
('202201010001', 100, '2022-01-01 10:10:10'), 
('202201020001', 300, '2022-01-02 10:10:10'),
('202202010001', 200, '2022-02-01 10:10:10');

第二步:实现按月分表的方式

定义分表规则

首先,我们需要定义分表规则,这里我们选择按照订单创建时间来进行分表,即每个月一张表。

创建分表的SQL语句

接下来,我们可以通过以下SQL语句来创建按月分表的订单表:

CREATE TABLE IF NOT EXISTS `order_{0}` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
  `order_amount` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

上面的语句中,{0}表示动态的表名后缀,例如表名为order_202201

实现分表的代码逻辑

最后,我们可以通过实现springboot的拦截器和多数据源来实现按月分表的逻辑。

首先,我们要实现拦截器,来根据订单创建的时间来判断应该使用哪个数据源,代码示例:

@Component
public class OrderTableInterceptor implements HandlerInterceptor {

    private static final String TABLE_PREFIX = "order_";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String orderNo = request.getParameter("orderNo");
        if (StringUtils.isEmpty(orderNo)) {
            throw new BusinessException("orderNo不能为空");
        }
        Date createTime = getOrderCreateTime(orderNo);
        if (createTime == null) {
            throw new BusinessException("获取订单创建时间失败");
        }

        String dataSourceKey = TABLE_PREFIX + DateUtil.format(createTime, "yyyyMM");
        DataSourceContextHolder.setDataSourceKey(dataSourceKey);
        return true;
    }

    /**
     * 根据订单号获取订单创建时间
     */
    private Date getOrderCreateTime(String orderNo) {
        // 查询订单,返回订单创建时间
        // 这里假设根据订单号从数据库中查询出来的订单创建时间为:2022-01-01 10:10:10
        return DateUtil.parse("2022-01-01 10:10:10");
    }
}

在上面的代码中,我们首先根据订单号获取订单创建时间,然后将订单创建时间格式化成表名的后缀,例如订单创建时间为2022-01-01 10:10:10,则表名后缀为202201。最后,使用DataSourceContextHolder来动态切换数据源。

接下来,我们还需要实现多数据源的配置和切换,这里我们采用springboot官方推荐的AbstractRoutingDataSource来实现,代码示例:

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }
}

其中,DataSourceContextHolder就是用来保存当前线程要使用的数据源的key。

最后,我们需要在springboot的配置文件中加入以下配置,来指定使用DynamicDataSource作为数据源:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/order?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    initial-size: 3
    min-idle: 3
    max-active: 500
    max-wait: 60000
    time-between-eviction-runs-millis: 60000
    min-evictable-idle-time-millis: 300000
    validation-query: SELECT 1 FROM DUAL
    test-while-idle: true
    test-on-borrow: false
    test-on-return: false

datasource:
  # 按月分表的数据源配置
  order_202201:
    url: jdbc:mysql://localhost:3306/order_202201?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  order_202202:
    url: jdbc:mysql://localhost:3306/order_202202?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

在上面的配置中,我们针对每个月的订单表都配置了一个单独的数据源。

第三步:测试

最后,我们可以通过以下代码来测试按月分表的实现方式:

@RestController
public class OrderController {

    @Autowired
    OrderMapper orderMapper;

    @GetMapping("/order")
    public List<Order> getOrderList(@RequestParam String orderNo) {
        return orderMapper.getOrderList(orderNo);
    }

    @PostMapping("/order")
    public Order addOrder(@RequestBody Order order) {
        orderMapper.addOrder(order);
        return order;
    }
}

其中,OrderMapper是用来操作数据库的Mapper,在里面会使用我们刚刚实现的动态数据源的逻辑。在测试时,可以通过Postman等工具来发送请求,例如:

  • GET http://localhost:8080/order?orderNo=202201010001
  • POST http://localhost:8080/order

测试成功后,就可以使用按月分表的方式来快速的拆分大量的订单数据了。

示例

下面是两个示例:

示例1

假设当前时间为2022年1月,我们要添加一个订单,订单创建时间为2022年1月3日,订单号为202201030001。发送POST请求如下:

POST http://localhost:8080/order
Content-Type: application/json

{
    "orderNo": "202201030001",
    "orderAmount": 200,
    "createTime": "2022-01-03 00:00:00"
}

返回结果如下:

{
    "id": 4,
    "orderNo": "202201030001",
    "orderAmount": 200.00,
    "createTime": "2022-01-03T00:00:00.000+00:00"
}

在数据库中,会自动创建一张名为order_202201的订单表,并且将该订单插入到该表中。

示例2

假设现在要查询订单号为202201010001的订单,发送GET请求如下:

GET http://localhost:8080/order?orderNo=202201010001

返回结果如下:

[
    {
        "id": 1,
        "orderNo": "202201010001",
        "orderAmount": 100.00,
        "createTime": "2022-01-01T10:10:10.000+00:00"
    }
]

在查询时,程序会根据订单创建时间来确定使用哪张表,例如该订单创建时间为2022年1月1日,所以会查询order_202201表,并返回查询结果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot 按月分表的实现方式 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Spring Bean是如何初始化的详解

    当Spring应用启动时,Spring容器会初始化所有由用户定义的bean(也就是Spring应用上下文中的bean),并映射它们之间的依赖关系。那么Spring Bean是如何初始化的呢?下面详细介绍一下Spring Bean的初始化过程。 1. Spring Bean的加载 首先,Spring容器会扫描Bean配置文件,找到所有的Bean定义,并将其保存…

    Java 2023年5月27日
    00
  • Sprint Boot @EnableAsync使用方法详解

    Spring Boot的@EnableAsync注解 在Spring Boot中,@EnableAsync注解用于启用异步方法的支持。使用@EnableAsync注解可以将带有@Async注解的方法标记为异步方法,并在调用这些方法时使用线程池来执行它们。本文将详细介绍@EnableAsync注解的作用和使用方法,并提供两个示例说明。 @EnableAsync…

    Java 2023年5月5日
    00
  • springboot处理异常的5种方式

    下面我会为您详细讲解Spring Boot处理异常的五种方式,过程中会包含两条示例。 1. 使用@ControllerAdvice @ControllerAdvice可以用来捕获Controller抛出的异常,然后做出相应的处理。需要在类上加上注解@ControllerAdvice来表示这是一个异常处理类,然后再配合上@ExceptionHandler注解来…

    Java 2023年5月27日
    00
  • Mybatis联合查询的实现方法

    下面是对于Mybatis联合查询的实现方法的详细讲解及示例。 1. 联合查询的概念 Mybatis的联合查询实际上是多表查询的一种实现方式,也就是说,它是通过对多个数据表进行连接查询,然后再将查询结果进行合并,最终得到一个包含所有所需数据的结果集。联合查询通常用于查询复杂的业务需求,例如需要返回关联表或多个表中的信息的场合。 2. 联合查询的实现方法 在My…

    Java 2023年5月20日
    00
  • Stream流排序数组和List 详解

    Stream流排序数组和List 详解 在 Java 8 中新增了 Stream 流,可以使用 Stream 流对数组和 List 进行排序。本文将详细介绍 Stream 流排序数组和 List 的方法以及示例。 Stream 流排序数组 对于数组排序,我们可以使用 Arrays 类中的 sort 方法,该方法可以对基本类型和实现 Comparable 接口…

    Java 2023年5月26日
    00
  • iis、apache、nginx使用X-Frame-Options防止网页被Frame的解决方法

    在Web开发中,防止网页被Frame劫持成为了必须的安全措施之一,其中一个重要的方式是使用HTTP响应头中的“X-Frame-Options”来限制哪些网站可以使用Frame加载该网页。 不同的Web服务器软件可能实现方式略有不同,以下分别介绍如何在IIS、Apache以及Nginx中使用X-Frame-Options来防止网页被Frame。 IIS中使用X…

    Java 2023年6月15日
    00
  • 通过Java组合问题看透回溯法

    通过Java组合问题看透回溯法的完整攻略可以分为以下几个步骤: 1. 确定问题模型 首先,我们需要确定问题模型。以Java组合问题为例,问题模型是在给定的n个数字中,任选k个数字,求它们的组合。 2. 定义回溯函数 接下来,我们需要定义回溯函数。回溯函数是实现回溯功能的主要函数。以Java组合问题为例,回溯函数需要有以下参数:- nums:可选数字的集合- …

    Java 2023年5月19日
    00
  • Java中String类(字符串操作)的10个常见问题和解决方法

    Java中String类的10个常见问题和解决方法 在Java中,String类是非常常见的引用类型,用于表示字符串。然而,由于String类的一些特性,我们在使用String类时可能会遇到一些问题。在本篇文章中,我们将讨论Java中String类的10个常见问题和解决方法。 1. 字符串比较 在Java中比较两个字符串应该使用equals()方法而不是’=…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部