Spring Boot 实现分布式定时任务锁 shedlock

分布式定时任务有好几种实现,我这里用了mysql和redis来实现
我们在项目中经常要用到定时任务,当有天服务器压力过大,我们就会增加服务器的数量,这时每台服务器的定时任务都在同一时间运行,导致我们需要同一时间运行一次的定时任务跑了多次,这时就需要解决这个问题,就用到了 shedlock

下面这是我项目里写的定时任务,里面的方法没有写出来

@Component
public class TimeOutSMSScheduledLock {

    @Autowired
    public TimeOutSMSService timeOutSMSService;

	//这时定时任务
    @Scheduled(cron = "0 0 9,14 * * ?")
    public void sendSMS(){
    	//具体的方法我就不写了,你可以随便写也可以打印日志
        timeOutSMSService.timeOutSendSMS();
    }
}

一、mysql实现分布式定时任务锁

依赖:

<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-spring</artifactId>
	<version>2.2.0</version>
</dependency>
<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);
    }
}

然后在数据库建一张表

CREATE TABLE `shedlock` (
  `name` varchar(64) NOT NULL DEFAULT '',
  `lock_until` timestamp NULL DEFAULT NULL,
  `locked_at` timestamp NULL DEFAULT NULL,
  `locked_by` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

里面有四个字段:

  • 主键name:每个定时任务的一个名字
  • locked_at:锁的开始时间
  • lock_until:锁的结束时间

再定时开始时,会更新这两个时间,在时间之内的定时是不会被执行的

在这里插入图片描述

在启动类上加@EnableSchedulerLock注解

@SpringBootApplication
//启用自带定时任务
@EnableScheduling
//定时任务锁
//defaultLockAtMostFor 指定在执行节点结束时应保留锁的默认时间使用ISO8601 Duration格式
//作用就是在被加锁的节点挂了时,无法释放锁,造成其他节点无法进行下一任务
//这里默认30s
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class CmccVoicesApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(CmccVoicesApiApplication.class, args);
	}
}

在方法上加@SchedulerLock注解

@Component
public class TimeOutSMSScheduledLock {

	@Autowired
	public TimeOutSMSService timeOutSMSService;

	//这是定时任务
	@Scheduled(cron = "0 0 9,14 * * ?")
	//参数自己根据情况设置
	@SchedulerLock(name = "sugExpiredSMS", lockAtMostFor = 1000*60*60*10, lockAtLeastFor = 1000*60*60*5)
	public void sendSMS() {
		//具体的方法我就不写了,你可以随便写也可以打印日志
		timeOutSMSService.timeOutSendSMS();
	}
}
  • name:定时任务的名字,就是数据库中的内个主键
  • lockAtMostFor:锁的最大时间单位为毫秒
  • lockAtMostForString:最大时间的字符串形式,例如:PT30S 代表30秒
  • lockAtLeastFor:锁的最小时间单位为毫秒
  • lockAtLeastForString:最小时间的字符串形式

这样mysql的分布式定时任务锁就完成了

二、redis 实现分布式定时任务锁

redis其实和mysql类似,只是配置和导包的不同

依赖

<!-- 分布式定时任务锁 -->
<!-- https://mvnrepository.com/artifact/net.javacrumbs.shedlock/shedlock-spring -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-spring</artifactId>
	<version>4.0.4</version>
</dependency>
<!-- 使用redis做分布式任务 -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-provider-redis-spring</artifactId>
	<version>2.5.0</version>
</dependency>

配置 shedlock 和 redis

@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M")
public class ShedLockConfig {

	@Bean
	public LockProvider lockProvider(RedisTemplate redisTemplate) {
		return new RedisLockProvider(redisTemplate.getConnectionFactory());
	}
}

在启动类上添加注解

@SpringBootApplication
//这个是定时任务,必须要有
@EnableScheduling
public class AppsApplication {

	public static void main(String[] args) {
		SpringApplication.run(AppsApplication .class, args);
	}
}

在定时任务上加注解@SchedulerLock,这里和mysql是一样

@Component
public class TimeOutSMSScheduledLock {

	@Autowired
	public TimeOutSMSService timeOutSMSService;

	//这是定时任务
	@Scheduled(cron = "0 0 9,14 * * ?")
	//参数自己根据情况设置
	@SchedulerLock(name = "sugExpiredSMS", lockAtMostFor = 1000*60*60*10, lockAtLeastFor = 1000*60*60*5)
	public void sendSMS() {
		//具体的方法我就不写了,你可以随便写也可以打印日志
		timeOutSMSService.timeOutSendSMS();
	}
}

这样redis的分布式定时任务锁完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值