问题描述

负载均衡的项目如果用了Quartz定时任务,到了指定执行时间,定时任务就会被执行多次,而我希望只执行一次

解决办法

在定时任务代码的开头,使用Redis的SETNX命令设置一个键,设置成功才继续执行下面的代码,从而实现只执行一次定时任务

实现代码

定义一个方法使用SETNX命令,这个方法给定时任务的代码使用,有注释的代码为关键代码,其上面和下面的代码为打开和关闭Redis连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 使用SETNX命令设置key-value键值对
*
* @param key 键名
* @param value 值
* @param seconds 秒数
* @return 设置成功返回true,否则返回false
*/
public static boolean setKeyNxSuccess(String key, String value, int seconds) {
JedisPool jedisPool = getRedisLink();
Jedis jedis = getJedis(jedisPool);
//setnx设置成功返回1,否则返回0
boolean result = (jedis.setnx(key, value) == 1);
//设置过期时间
setKeyTime(key, seconds);
closeRedis(jedisPool, jedis);
return result;
}

调用上面的代码实现只执行一次定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.ledao.quartz;

import com.ledao.util.RedisUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

/**
* @author LeDao
* @company
* @createDate 2023-12-27 18:33
*/
@Configuration
@EnableScheduling
public class AddTodayVisitorCountToDatabase {

@Scheduled(cron = "50 59 23 * * ?")
public void work() {

// 设置一个标记,设置该标记成功后才执行下面的代码,防止重复执行
boolean flag = RedisUtil.setKeyNxSuccess("setKeyNxSuccess", "1", 10);
if (flag) {
// 这里写业务代码

} else {
System.out.println(LocalDateTime.now() + "定时任务已经执行过了");
}
}
}