用shedlock实现分布式定时任务锁

转载自:
https://www.cnblogs.com/gutousu/p/10235160.html

spring的定时任务经常被各个服务用到,比如定时清理日志,定时提醒,

比较方便的就是用Scheduled注解了

简单的配置一下就能用了

@EnableScheduling
@SpringBootApplication
public class ScheduledLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScheduledLockApplication.class, args);
    }
} 

这里每2秒打印一下当前时间

@Component
public class ScheduledLock
{
    @Scheduled(cron = "0/2 * * * * ?")
    public void run()
    {
        System.out.print(new Date().toString() + "\n");
    }
}

但是!
有一天服务的压力过大,一个服务支撑不住了,我们要考虑部署多个服务来分散压力
这时问题就来了
你突然发现你的定时系统,在各个服务上全她丫的跑起来了,做着同样的事情,这必然不是我们想要的结果
这时你一定会想办法,让定时只执行一次
比如一个服务一个配置文件,在配置文件中控制定时的开关
再比如通过数据库的读写来控制定时的开关
详尽任何办法,其实这些都是一些不错的解决办法
但是!
有一个更方便的东西
那就是shedlock
就叫她分布式定时任务锁吧
她的锁分好多种
Mongo,Redis,Hazelcast,ZooKeeper,还有所有带JDBC的东西
这玩意用起来也特简单
她的包

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>2.2.0</version>
</dependency>

这里用JDBC的锁
再添加一个包

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>2.2.0</version>
</dependency>

对她进行一下配置,创建一个她要用的bean

@Configuration
public class ScheduledLockConfig
{
    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }
    @Bean
    public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
        return ScheduledLockConfigurationBuilder
                .withLockProvider(lockProvider)
                .withPoolSize(10)
                .withDefaultLockAtMostFor(Duration.ofMinutes(10))
                .build();
    }
}
  

我用的mysql数据库
在数据库中添加一张名为shedlock表

CREATE TABLE `shedlock` (
  `name` varchar(765) DEFAULT NULL,
  `lock_until` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `locked_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `locked_by` varchar(765) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在这里插入图片描述
这张表也是她要用的,她通过修改数据库表中的数据实现锁
里面有四个字段
主键name:每个定时任务的一个名字
locked_at:锁的开始时间
lock_until:锁的结束时间
再定时开始时,会更新这两个时间,在时间之内的定时是不会被执行的

在启动类上加上注解EnableSchedulerLock,开启定时任务锁,指定一个默认的锁的时间

@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
@SpringBootApplication
public class ScheduledLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScheduledLockApplication.class, args);
    }
}

在栗子中添加注解SchedulerLock

@Component
public class ScheduledLock
{
    private static final int lockTime = 1000;
 
    @Scheduled(cron = "0/2 * * * * ?")
    @SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtMostFor = lockTime, lockAtLeastFor = lockTime)
    public void run()
    {
        System.out.print(new Date().toString() + "\n");
    }
}
  

这个注解有五个参数

name:定时任务的名字,就是数据库中的内个主键
lockAtMostFor:锁的最大时间单位为毫秒
lockAtMostForString:最大时间的字符串形式,例如:PT30S 代表30秒
lockAtLeastFor:锁的最小时间单位为毫秒
lockAtLeastForString:最小时间的字符串形式

好了,起两个项目让她跑起来,看看结果

在这里插入图片描述

虽然不是很规律,但是没有重复的时间

发布了402 篇原创文章 · 获赞 60 · 访问量 71万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章