当前位置: 首页 > article >正文

springboot 如何删除上亿的数据?

在 Spring Boot 中删除上亿条数据是一个具有挑战性的任务,因为直接一次性删除大量数据可能会导致数据库性能问题、事务超时、锁表等。以下从不同角度介绍一些可行的方法。

1. 分批删除

分批删除是一种常见且有效的策略,将大量数据分成较小的批次进行删除操作,避免一次性处理过多数据对数据库造成过大压力。以下是使用 Spring Data JPA 实现分批删除的示例代码:

实体类

收起

java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class LargeData {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // 其他属性和 Getter、Setter 方法
    // 为简洁起见,这里省略
}
数据访问层(Repository)

收起

java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface LargeDataRepository extends JpaRepository<LargeData, Long> {
    @Transactional
    @Modifying
    @Query("DELETE FROM LargeData WHERE id IN :ids")
    void deleteByIds(List<Long> ids);
}
服务层

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class LargeDataService {
    @Autowired
    private LargeDataRepository largeDataRepository;

    private static final int BATCH_SIZE = 1000;

    @Transactional
    public void deleteLargeData() {
        List<LargeData> allData = largeDataRepository.findAll();
        List<Long> idsToDelete = new ArrayList<>();
        for (LargeData data : allData) {
            idsToDelete.add(data.getId());
            if (idsToDelete.size() == BATCH_SIZE) {
                largeDataRepository.deleteByIds(idsToDelete);
                idsToDelete.clear();
            }
        }
        if (!idsToDelete.isEmpty()) {
            largeDataRepository.deleteByIds(idsToDelete);
        }
    }
}
控制器层

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LargeDataController {
    @Autowired
    private LargeDataService largeDataService;

    @GetMapping("/delete-large-data")
    public String deleteLargeData() {
        largeDataService.deleteLargeData();
        return "Data deleted successfully";
    }
}

2. 基于条件范围删除

如果数据具有一定的范围属性(如时间、编号等),可以按照范围分批删除。例如,根据时间范围删除数据:

数据访问层(Repository)添加方法

收起

java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

public interface LargeDataRepository extends JpaRepository<LargeData, Long> {
    @Transactional
    @Modifying
    @Query("DELETE FROM LargeData WHERE createTime BETWEEN :startDate AND :endDate")
    void deleteByTimeRange(Date startDate, Date endDate);
}
服务层修改

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Date;

@Service
public class LargeDataService {
    @Autowired
    private LargeDataRepository largeDataRepository;

    private static final int DAYS_RANGE = 30;

    @Transactional
    public void deleteLargeDataByTimeRange() {
        Calendar calendar = Calendar.getInstance();
        Date endDate = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -DAYS_RANGE);
        Date startDate = calendar.getTime();

        while (startDate.before(endDate)) {
            largeDataRepository.deleteByTimeRange(startDate, endDate);
            calendar.add(Calendar.DAY_OF_MONTH, -DAYS_RANGE);
            endDate = startDate;
            startDate = calendar.getTime();
        }
    }
}

3. 利用数据库特性

不同的数据库有不同的优化删除大量数据的方法:

MySQL

  • 使用 TRUNCATE 语句:如果要删除整个表的数据,TRUNCATE 比 DELETE 更快,因为它不记录每一行的删除操作,而是直接释放表空间。但 TRUNCATE 不能带条件,会删除整个表的数据。

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class LargeDataService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void truncateTable() {
        jdbcTemplate.execute("TRUNCATE TABLE large_data");
    }
}
PostgreSQL

  • 使用 DELETE 结合 LIMIT:可以在 DELETE 语句中使用 LIMIT 分批删除数据。

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class LargeDataService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final int BATCH_SIZE = 1000;

    public void deleteLargeData() {
        int deletedRows;
        do {
            deletedRows = jdbcTemplate.update("DELETE FROM large_data WHERE id IN (SELECT id FROM large_data LIMIT ?)", BATCH_SIZE);
        } while (deletedRows > 0);
    }
}

4. 考虑性能优化

  • 关闭自动提交:在进行大量删除操作时,关闭自动提交事务,手动控制事务的提交和回滚,可以减少事务开销。

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class LargeDataService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void deleteLargeData() {
        // 执行删除操作
        jdbcTemplate.execute("DELETE FROM large_data WHERE some_condition");
    }
}

  • 索引处理:在删除大量数据前,可以考虑暂时禁用或删除相关索引,删除完成后再重新创建索引,这样可以减少删除过程中索引维护的开销。

5. 异步处理

由于删除大量数据可能会花费较长时间,为了避免阻塞主线程影响系统的响应性能,可以使用异步处理。在 Spring Boot 中可以使用 @Async 注解实现异步方法:

开启异步支持

在主应用类上添加 @EnableAsync 注解:

收起

java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
服务层添加异步方法

收起

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class LargeDataService {
    @Autowired
    private LargeDataRepository largeDataRepository;

    @Async
    @Transactional
    public void deleteLargeDataAsync() {
        // 执行删除逻辑
    }
}

通过上述方法,可以在 Spring Boot 中较为安全、高效地删除上亿条数据。具体使用哪种方法,需要根据数据特点、数据库类型和业务需求来决定。


http://www.kler.cn/a/561970.html

相关文章:

  • 游戏客户端架构设计与实战:从模块化到性能优化
  • OpenIPC开源FPV之Adaptive-Link安装
  • Python的那些事第三十二篇:用于创建静态、动画和交互式可视化的绘图库Matplotlib
  • 基于 ArcGIS Pro 与 R 的生态系统服务权衡与协同分析
  • DeepSeek掘金——SearpApi联网搜索 给DeepSeek插上翅膀
  • React 前端框架介绍
  • 如何获取zookeeper中的注册内容,在Java项目中演示
  • 2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷(二)
  • Django笔记1_简介
  • Python深度学习:遥感影像目标识别中的数据标注技巧
  • PC端-发票真伪查验系统-Node.js全国发票查询接口
  • 多模态人物视频驱动技术回顾与业务应用
  • 使用Python爬虫获取京东商品评论API接口的详细指南
  • 推理模型面试核心问题解析:方法与实战应用
  • 【MySQL】:四大排名函数
  • 【DeepSeek系列】05 DeepSeek核心算法改进点总结
  • Android AOSP系统裁记录
  • 算法——后缀树
  • 监控平台技术方案
  • 将 vue3 项目打包后部署在 springboot 项目运行