本文目录导读:

- Timer + TimerTask(简单方案)
- ScheduledExecutorService(推荐方案)
- Spring @Scheduled(企业级方案)
- 完整的清理实现示例(结合数据库)
- 使用Quartz(分布式场景)
- 最佳实践建议
在Java中实现定时清理数据的常见方案有以下几种,我会从简单到复杂逐一介绍:
Timer + TimerTask(简单方案)
适用于简单场景,单线程执行:
import java.util.Timer;
import java.util.TimerTask;
public class DataCleanupExample {
public static void main(String[] args) {
Timer timer = new Timer("DataCleanupTimer");
// 延迟1秒后开始,每24小时执行一次
timer.schedule(new TimerTask() {
@Override
public void run() {
cleanExpiredData();
}
}, 1000, 24 * 60 * 60 * 1000);
// 或者使用相对时间
// timer.schedule(new TimerTask() { ... }, new Date(), period);
}
private static void cleanExpiredData() {
System.out.println("开始清理过期数据...");
// 实际清理逻辑
// 比如删除7天前的日志
// DELETE FROM logs WHERE create_time < DATE_SUB(NOW(), INTERVAL 7 DAY)
}
}
ScheduledExecutorService(推荐方案)
这是JDK推荐的方案,支持多线程:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledCleanupExample {
private final ScheduledExecutorService scheduler;
public ScheduledCleanupExample() {
// 创建线程池,通常1-2个线程就够
this.scheduler = Executors.newScheduledThreadPool(2);
}
public void startCleanupTask() {
// 初始延迟1秒,每30分钟执行一次
scheduler.scheduleAtFixedRate(() -> {
try {
performCleanup();
} catch (Exception e) {
// 异常处理,避免任务停止
System.err.println("清理任务失败: " + e.getMessage());
}
}, 1, 30, TimeUnit.MINUTES);
}
private void performCleanup() {
System.out.println("[" + new java.util.Date() + "] 执行数据清理...");
// 示例:清理7天前的数据
cleanupOldRecords("logs", 7);
cleanupOldRecords("temp_files", 3);
}
private void cleanupOldRecords(String table, int days) {
// 实际数据库操作
// String sql = "DELETE FROM " + table + " WHERE create_time < ?";
// jdbcTemplate.update(sql, new java.util.Date(System.currentTimeMillis() -
// (long) days * 24 * 60 * 60 * 1000));
System.out.println("清理表 " + table + " 中" + days + "天前的数据");
}
public void shutdown() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
public static void main(String[] args) {
ScheduledCleanupExample example = new ScheduledCleanupExample();
example.startCleanupTask();
// 程序运行时保持运行
Runtime.getRuntime().addShutdownHook(new Thread(example::shutdown));
}
}
Spring @Scheduled(企业级方案)
如果你的项目使用Spring框架,这是最简单的方式:
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling
public class ScheduledDataCleanup {
// 每天凌晨2点执行
@Scheduled(cron = "0 0 2 * * ?")
public void cleanupDailyData() {
System.out.println("执行每日数据清理...");
// 清理逻辑
}
// 每30分钟执行一次
@Scheduled(fixedRate = 30 * 60 * 1000)
public void cleanupTempData() {
System.out.println("清理临时数据...");
// 清理逻辑
}
// 上次执行完后延迟10分钟再执行
@Scheduled(fixedDelay = 600000)
public void cleanupAfterPrevious() {
System.out.println("上次清理完成后10分钟再执行...");
}
// 带初始延迟的任务
@Scheduled(initialDelay = 5000, fixedRate = 3600000)
public void cleanupWithDelay() {
// 启动5秒后,每小时执行一次
}
}
完整的清理实现示例(结合数据库)
import java.sql.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DatabaseDataCleanup {
private static final String DB_URL = "jdbc:mysql://localhost:3306/mydb";
private static final String DB_USER = "root";
private static final String DB_PASS = "password";
public void cleanOldRecords() {
String sql = "DELETE FROM user_logs WHERE create_time < ?";
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置7天前的时间
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(7);
pstmt.setObject(1, cutoffDate);
int deletedCount = pstmt.executeUpdate();
System.out.println("清理了 " + deletedCount + " 条过期记录");
} catch (SQLException e) {
System.err.println("数据库清理失败: " + e.getMessage());
}
}
// 批量清理,避免大事务
public void batchCleanup() {
int batchSize = 1000;
String sql = "DELETE FROM logs WHERE create_time < ? LIMIT ?";
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(30);
int totalDeleted = 0;
while (true) {
pstmt.setObject(1, cutoffDate);
pstmt.setInt(2, batchSize);
int deleted = pstmt.executeUpdate();
totalDeleted += deleted;
if (deleted < batchSize) {
break; // 没有更多数据可删除
}
// 稍微暂停,避免数据库压力过大
Thread.sleep(100);
}
System.out.println("总共清理了 " + totalDeleted + " 条记录");
} catch (SQLException | InterruptedException e) {
System.err.println("批量清理失败: " + e.getMessage());
}
}
}
使用Quartz(分布式场景)
对于分布式系统,推荐使用Quartz框架:
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzCleanupExample {
public static void main(String[] args) throws SchedulerException {
// 1. 定义Job
JobDetail job = JobBuilder.newJob(CleanupJob.class)
.withIdentity("dataCleanupJob", "cleanupGroup")
.build();
// 2. 定义触发器(每天凌晨3点)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cleanupTrigger", "cleanupGroup")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 3 * * ?"))
.build();
// 3. 启动调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
// 自定义Job
class CleanupJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("执行定时清理任务...");
// 清理逻辑
}
}
最佳实践建议
-
选择合适的方案:
- 简单应用:
ScheduledExecutorService - Spring应用:
@Scheduled - 分布式系统:
Quartz或XXL-JOB
- 简单应用:
-
异常处理:确保任务不会因为一次失败就停止
-
日志记录:记录清理的开始、结束和执行情况
-
幂等性设计:确保多次执行结果一致
-
分批处理:大量数据时避免大事务
-
监控告警:清理失败时要能及时发现
选择哪种方案取决于你的项目规模、框架使用情况和业务复杂度。