spring boot 集群 定时任务下,解决 重复执行的任务

方案一:

思路:放置一个开关标识,然后在启动项目时,spring会自动加载这个定时任务类,通过类上的注解判断是否加载该实例,如果不加载,就不会执行定时任务

缺点:只能指定某一个服务【单体情况适用】,集群下还是不能解决该问题

在yml配置文件中添加 例如:

scheduling:
    enabled: true

然后在定时任务类上添加注解


@Component
@ConditionalOnProperty(prefix = "scheduling",name="enabled",havingValue="true") //该注解满足参数条件才会加载该类    ,配置文件是true,    havingValue="false"该类就不会执行定时任务
public class task{

    
}

 

方案二(本次问题使用的方案):

添加redis 分布式锁

首先先添加pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

配置文件中 配置redis 参数

创建redis分布式锁工具类

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * @ClassName RedisLock
 * @Description
 * @Author zsw
 * @Date 2021/1/21 16:48
 * @Version V1.0
 **/
@Slf4j
public class RedisLock implements AutoCloseable {

    private RedisTemplate redisTemplate;

    private String key;

    private String value;

    private int expireTime;

    public RedisLock(RedisTemplate redisTemplate, String key, int expireTime) {
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.value = UUID.randomUUID().toString()+"_"+ IPUtil.getLocalIp();
        this.expireTime = expireTime;
    }



    public boolean getLock(){
        RedisCallback<Boolean> redisCallback = connection ->{
            RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
            Expiration seconds = Expiration.seconds(expireTime);
            byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
            byte[] redisValue = redisTemplate.getKeySerializer().serialize(value);
            Boolean result = connection.set(redisKey, redisValue, seconds, setOption);
            return result;
        };
        boolean execute = (boolean)redisTemplate.execute(redisCallback);
        return execute;
    }


    public boolean unLock(){
        StringBuffer sb = new StringBuffer();
        sb.append("if  redis.call(\"get\",KEYS[1]) == ARGV[1] then\n");
        sb.append("return redis.call(\"del\",KEYS[1])\n");
        sb.append("else \n");
        sb.append("return 0\n");
        sb.append("end");

        RedisScript of = RedisScript.of(sb.toString(), Boolean.class);
        List<String> keys = Arrays.asList(key);
        boolean execute = (boolean)redisTemplate.execute(of, keys, value);

        return execute;

    }


    @Override
    public void close() throws Exception {

    }
}

如何使用呢?

public class task{


        @Scheduling(fixedRate = 1000 * 10)
        public void task1(){
            try(RedisLock redisLock = new RedisLock(redisTemplate,"key",1000 *9 )){ //定时任务是每次隔10s执行,锁是9秒后就过期释放了或者执行完就释放了
                
                if(redisLock .getLock()){
                        //执行业务...
                    
                }catch(Exception e){
                        
                }
            }
            
        } 

}

备注: 方案一和方案二也可以搭配使用

 

 

其他方案:待研究quartz。。。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值