• 基于分布式锁解决定时任务重复问题


    一、基于分布式锁解决定时任务重复问题

     1、定时任务部署集群

    二、利用redis分布式锁解决定时任务重复发送短信

    1、启用定时任务

    package com.example.distributelock;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @SpringBootApplication
    @MapperScan("com.example.distributelock.dao")
    @EnableScheduling
    public class DistributeLockApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DistributeLockApplication.class, args);
        }
    
    }
    View Code

    2、定时的任务业务代码

    package com.example.distributelock.service;
    
    import com.example.distributelock.lock.RedisLock;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    @Slf4j
    public class SchedulerService {
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Scheduled(cron = "0/5 * * * * ?")
        public void sendSms(){
            try(RedisLock redisLock = new RedisLock(redisTemplate,"autoSms",30)) {
                if (redisLock.getLock()){
                    log.info("向138xxxxxxxx发送短信!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    3、核心类 RedisLock

       自动释放 AutoCloseable

    package com.example.distributelock.lock;
    
    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;
    
    @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.expireTime=expireTime;
            this.value = UUID.randomUUID().toString();
        }
    
        /**
         * 获取分布式锁
         * @return
         */
        public boolean getLock(){
            RedisCallback<Boolean> redisCallback = connection -> {
                //设置NX
                RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
                //设置过期时间
                Expiration expiration = Expiration.seconds(expireTime);
                //序列化key
                byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
                //序列化value
                byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);
                //执行setnx操作
                Boolean result = connection.set(redisKey, redisValue, expiration, setOption);
                return result;
            };
    
            //获取分布式锁
            Boolean lock = (Boolean)redisTemplate.execute(redisCallback);
            return lock;
        }
    
        public boolean unLock() {
            String script = "if redis.call("get",KEYS[1]) == ARGV[1] then
    " +
                    "    return redis.call("del",KEYS[1])
    " +
                    "else
    " +
                    "    return 0
    " +
                    "end";
            RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class);
            List<String> keys = Arrays.asList(key);
    
            Boolean result = (Boolean)redisTemplate.execute(redisScript, keys, value);
            log.info("释放锁的结果:"+result);
            return result;
        }
    
    
        @Override
        public void close() throws Exception {
            unLock();
        }
    }
    View Code
  • 相关阅读:
    JZ-C-36
    JZ-C-35
    JZ-C-34
    JZ-C-33
    JZ-C-32
    JZ-C-31
    JZ-C-30
    JZ-C-29
    JZ-C-28
    JZ-C-27
  • 原文地址:https://www.cnblogs.com/callbin/p/14583834.html
Copyright © 2020-2023  润新知