实现一百万条数据的状态秒级更新!

点击上方“程序员蜗牛g”,选择“设为星标”

跟蜗牛哥一起,每天进步一点点

程序员蜗牛g

大厂程序员一枚 跟蜗牛一起 每天进步一点点

31篇原创内容

公众号

为了提高订单状态更新的效率和系统的响应能力,我们决定采用分布式任务调度实现高效的订单状态批量更新。

应用场景

数据批处理

  • 批量数据导入/导出:将大量数据从一个系统迁移到另一个系统时,可以将数据分成多个批次进行处理。

  • 日志处理:分析和处理大量的日志文件,每个分片处理一部分日志。

实时监控与报警

  • 监控指标收集:实时收集和处理监控指标,每个分片负责收集一部分系统的监控数据。

  • 报警规则评估:评估报警规则,每个分片处理一部分报警条件。

任务分片的目的

    图片

    如何进行任务分片?

      图片

      代码实操

          <!-- Spring Boot Starter -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
          </dependency>
      
          <!-- Spring Data JPA -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-jpa</artifactId>
          </dependency>
      
          <!-- MySQL Connector -->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <scope>runtime</scope>
          </dependency>
      
          <!-- ElasticJob Lite Core -->
          <dependency>
              <groupId>com.dangdang</groupId>
              <artifactId>elastic-job-lite-core</artifactId>
              <version>2.1.5</version>
          </dependency>
      
          <!-- ElasticJob Lite Spring Boot Starter -->
          <dependency>
              <groupId>com.dangdang</groupId>
              <artifactId>elastic-job-lite-spring-boot-starter</artifactId>
              <version>2.1.5</version>
          </dependency>
      
          <!-- Zookeeper Client -->
          <dependency>
              <groupId>org.apache.curator</groupId>
              <artifactId>curator-framework</artifactId>
              <version>4.2.0</version>
          </dependency>
          <dependency>
              <groupId>org.apache.curator</groupId>
              <artifactId>curator-recipes</artifactId>
              <version>4.2.0</version>
          </dependency>
      

      application.yml

      server:
        port:8080
      
      spring:
      datasource:
          url:jdbc:mysql://localhost:3306/order_db?useSSL=false&serverTimezone=UTC
          username:root
          password:123456
          driver-class-name:com.mysql.cj.jdbc.Driver
      
      jpa:
          hibernate:
            ddl-auto:update
          show-sql:true
          properties:
            hibernate:
              dialect:org.hibernate.dialect.MySQL5InnoDBDialect
      
      elasticjob:
      regCenter:
          serverLists:localhost:2181# ZooKeeper服务器地址
          namespace:elastic-job-demo   # 命名空间
      jobs:
          orderStatusUpdateJob:
            cron: 0 0 * * * ?     # Cron表达式,每小时执行一次
            shardingTotalCount:5   # 分片总数
            jobClass:com.example.job.OrderStatusUpdateJob# 任务类全限定名
            description:"更新订单状态"# 任务描述
      

      Application.java

      package com.example;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.scheduling.annotation.EnableScheduling;
      
      @SpringBootApplication
      @EnableScheduling  // 启用定时任务调度
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
      

      订单状态更新任务

      package com.example.job;
      
      import com.dangdang.ddframe.job.api.ShardingContext;
      import com.dangdang.ddframe.job.simple.api.SimpleJob;
      import com.example.service.OrderService;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      /**
       * 订单状态更新任务类
       * 实现SimpleJob接口,用于定期更新订单状态
       */
      @Component
      publicclass OrderStatusUpdateJob implements SimpleJob {
      
          privatestaticfinal Logger log = LoggerFactory.getLogger(OrderStatusUpdateJob.class);
      
          @Autowired
          private OrderService orderService;  // 注入OrderService服务
      
          /**
           * 执行任务的方法
           * @param context 分片上下文
           */
          @Override
          public void execute(ShardingContext context) {
              int shardingItem = context.getShardingItem();  // 获取当前分片项
              int shardingTotalCount = context.getShardingTotalCount();  // 获取总分片数
              long maxOrderId = orderService.getMaxOrderId();  // 获取最大订单ID
      
              // 计算当前分片需要处理的订单范围
              long startId = (long) shardingItem * (maxOrderId / shardingTotalCount);
              long endId = Math.min(startId + (maxOrderId / shardingTotalCount), maxOrderId);
      
              log.info("Processing orders from {} to {}", startId, endId);  // 记录处理的订单范围
              int updatedCount = orderService.updateStatusInRange(startId, endId, "Processed");  // 更新订单状态
      
              log.info("Updated {} orders in range {} to {}", updatedCount, startId, endId);  // 记录更新结果
          }
      }
      

      订单实体类

      package com.example.model;
      
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      
      /**
       * 订单实体类
       * 映射到数据库中的order表
       */
      @Entity
      publicclass Order {
      
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Long id;  // 订单ID
      
          private String status;  // 订单状态
      
          public Long getId() {
              return id;
          }
      
          public void setId(Long id) {
              this.id = id;
          }
      
          public String getStatus() {
              return status;
          }
      
          public void setStatus(String status) {
              this.status = status;
          }
      }
      

      订单Repository

      package com.example.repository;
      
      import com.example.model.Order;
      import org.springframework.data.jpa.repository.JpaRepository;
      import org.springframework.data.jpa.repository.Modifying;
      import org.springframework.data.jpa.repository.Query;
      import org.springframework.data.repository.query.Param;
      import org.springframework.transaction.annotation.Transactional;
      
      import java.util.List;
      
      /**
       * 订单Repository接口
       * 提供基本的CRUD操作和自定义查询
       */
      publicinterface OrderRepository extends JpaRepository<Order, Long> {
      
          /**
           * 根据ID范围查找订单
           * @param startId 开始ID
           * @param endId 结束ID
           * @return 订单列表
           */
          List<Order> findByIdBetween(Long startId, Long endId);
      
          /**
           * 根据ID范围更新订单状态
           * @param startId 开始ID
           * @param endId 结束ID
           * @param newStatus 新状态
           * @return 更新的订单数量
           */
          @Modifying
          @Transactional
          @Query("UPDATE Order o SET o.status = :newStatus WHERE o.id BETWEEN :startId AND :endId")
          int updateStatusInRange(@Param("startId") Long startId, @Param("endId") Long endId, @Param("newStatus") String newStatus);
      }
      

      订单服务类

      package com.example.service;
      
      import com.example.model.Order;
      import com.example.repository.OrderRepository;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * 订单服务类
       * 处理订单相关的业务逻辑
       */
      @Service
      publicclass OrderService {
      
          @Autowired
          private OrderRepository orderRepository;  // 注入OrderRepository
      
          /**
           * 根据ID范围获取订单
           * @param startId 开始ID
           * @param endId 结束ID
           * @return 订单列表
           */
          public List<Order> getOrdersByRange(Long startId, Long endId) {
              return orderRepository.findByIdBetween(startId, endId);
          }
      
          /**
           * 根据ID范围更新订单状态
           * @param startId 开始ID
           * @param endId 结束ID
           * @param newStatus 新状态
           * @return 更新的订单数量
           */
          public int updateStatusInRange(Long startId, Long endId, String newStatus) {
              return orderRepository.updateStatusInRange(startId, endId, newStatus);
          }
      
          /**
           * 获取最大订单ID
           * @return 最大订单ID
           */
          public long getMaxOrderId() {
              return orderRepository.findAll().stream()
                      .mapToLong(Order::getId)
                      .max()
                      .orElse(0L);
          }
      }
      

      如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值