1.定位定时任务所走方法
-
打方法断点
随便找一个定时任务的方法类,打断点查看执行过程
-
执行方法
点击立即执行,执行该方法
-
定位方法
点击步过,寻找合适的代码位置增加分布式锁
最终看到方法在此处进行返回,我们可以再此处进行加锁操作
2.添加分布式锁
-
引入redisson依赖,添加配置类
在ruoyi-common pom引入redisson依赖
<!--Redisson redis若依已经引入-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.4</version>
</dependency>
添加配置类
package com.ruoyi.common.core.redis;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Cxt
* @Description redisson配置
* @Date 2023/6/29 15:47
* @Version 1.0
*/
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
// 配置Redisson连接信息
config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(null);
return Redisson.create(config);
}
}
-
引入redisson服务
如果开启了ScheduleConfig类 注入方式请改为如下图所示注入
-
修改原有的方法
在处理好sysJob对象后 根据任务名称来创建锁对象
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
SysJob sysJob = new SysJob();
BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
try
{
before(context, sysJob);
if (sysJob != null)
{
//创建锁对象
RLock lock = redissonClient.getLock(ScheduleConstants.TASK_PROPERTIES);
//尝试获取锁
boolean isLock = lock.tryLock();
if (!isLock){
throw new ServiceException("该任务正在执行中!");
}
try{
//真正执行的方法
doExecute(context, sysJob);
}finally {
//释放锁
lock.unlock();
}
}
after(context, sysJob, null);
}
catch (Exception e)
{
log.error("任务执行异常 - :", e);
after(context, sysJob, e);
}
}
3.测试
同一时间如果拿不到锁将会直接失败,成功达到效果
特别注意
在拿到锁之后,由于走的是本地缓存,为了避免重复执行,请将任务策略改为放弃执行
官方方法
取消注释类ScheduleConfig即可(注意查看相关表是否存在)