手记

【redis系列一】基于redis分布式锁,解决定时任务重复执行问题

小编所在公司做的项目,大官人说要在项目中添加定时推送短信的功能,每周1推送一次,以便大官人可以不登录系统,知道还有什么紧急事情要处理。so接了任务,就得完成,所以我首先想到了使用定时任务+分布式锁来完成。定时任务定时发送短信,因为是集群部署,到时间点,每个服务器都要发送短信,怎么样只让一台服务器发送短信呢,所以要用到分布式锁,那台服务抢到锁,发送短信的任务就交给它。

背景交代清楚了,开始coding吧

第一步:写个定时任务

@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class SaticScheduleTask {
//3.添加定时任务
@Scheduled(cron = “0/5 * * * * ?”)
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() {
System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
}
}

第二步:写个分布式锁,小编使用set+lua脚本的方式,实现分布式锁。

@Slf4j
@RestController
@RequestMapping("/")
public class distributeLock {

@Autowired
private RedisTemplate redisTemplate;

/**
 * redis 分布式锁 : set+lua脚本
 */
@RequestMapping(value = "redisLock",method = RequestMethod.GET)
public String RedisLock(){
    // key是业务类型名称
    String key = "redisKey";
    // value是用来校验删除的是否是当前的线程的锁
    String value = UUID.randomUUID().toString();

    // 被回调函数,声明一个锁,作用是set一个值是否成功
    RedisCallback redisCallback = (connection)->{
        // nx,如果为false表示设置失败,为true表示该key未被设置过
        RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
        // 过期时间
        Expiration expiration = Expiration.seconds(30);
        byte[] keys = redisTemplate.getKeySerializer().serialize(key);
        byte[] values = redisTemplate.getValueSerializer().serialize(value);
        //set()来实现分布式锁
        Boolean result = connection.set(keys, values, expiration, setOption);
        return result;
    };

    // 执行set
    Boolean execute = (Boolean)redisTemplate.execute(redisCallback);
    if (execute){
        // 业务逻辑
        log.info("=====我获得了锁,进入了业务逻辑=====");
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 执行完毕业务之后,释放锁,使用lua脚本
            String lu = "if redis.call('get', KEYS[1]) == ARGV[1] \n" +
                    "    then \n" +
                    "\t    return redis.call('del', KEYS[1]) \n" +
                    "\t else \n" +
                    "\t    return 0 \n" +
                    "end";
            // 执行lua脚本
            RedisScript<Boolean> redisScript = RedisScript.of(lu, Boolean.class);
            List<String> keyss = Arrays.asList(key);
            Boolean bool = (Boolean)redisTemplate.execute(redisScript, keyss,value);

            log.info("释放锁的结果:"+bool);
        }
    }
    return null;
}

}

上面是个例子,仅供参考:

核心思想就是:多个服务器抢这把锁,谁抢到谁发送短信

作者:一起写程序

0人推荐
随时随地看视频
慕课网APP