若依-单机器多服务器定时任务重复执行问题解决-分布式锁

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即可(注意查看相关表是否存在)

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Redis 支持通过使用 Lua 脚本实现分布式锁。可以使用 Redis 的 SET 命令,并在设置锁时设置过期时间,以避免死锁。 以下是 Redisson 库中实现分布式锁的示例代码: ```java // 创建 RedissonClient 客户端 RedissonClient redisson = Redisson.create(); // 获取锁对象 RLock lock = redisson.getLock("lockName"); // 加锁,设置锁最长占用时间为10s lock.lock(10, TimeUnit.SECONDS); try { // do something } finally { // 释放锁 lock.unlock(); } ``` 注意: 1. 获取锁时需要捕获异常,确保释放锁,防止死锁 2. 为了保证锁能尽可能少时间持有,建议锁的持有时间尽可能短 以上代码使用redission来实现分布式锁,用于解决定时任务重复执行问题。 ### 回答2: Redission是一个开源的分布式锁框架,可以用于解决定时任务重复执行问题。下面是一个用Redission实现分布式锁的示例。 在使用Redission之前,需要在项目中添加对Redission依赖的引用。可以在项目的构建文件中添加相关依赖,然后按照文档的指示进行安装和配置。 首先,创建一个任务类,用于执行定时任务的逻辑。在任务类中,可以使用Redission获取分布式锁,并在获取到锁之后执行任务逻辑。在任务逻辑执行完成后,释放锁,以便其他节点能够获取锁执行任务。 下面是一个示例的任务类: ```java import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class ScheduledTask implements Runnable { private static final String LOCK_NAME = "myLock"; private static final String REDIS_HOST = "127.0.0.1"; private static final int REDIS_PORT = 6379; @Override public void run() { // 创建 Redisson 配置 Config config = new Config(); config.useSingleServer().setAddress("redis://" + REDIS_HOST + ":" + REDIS_PORT); // 创建 Redisson 客户端 RedissonClient redissonClient = Redisson.create(config); // 获取分布式锁 RLock lock = redissonClient.getLock(LOCK_NAME); try { // 尝试获取锁 if (lock.tryLock()) { // 执行任务逻辑 System.out.println("执行定时任务"); } } finally { // 释放锁 lock.unlock(); } } } ``` 在任务逻辑中,首先创建一个Redission的配置对象,并指定Redis的连接地址。然后创建一个Redission客户端对象。 接下来,通过Redission客户端对象获取一个分布式锁,使用tryLock方法尝试获取锁。如果成功获取到锁,则执行任务逻辑。 任务执行完成后,需要手动释放锁,以便其他节点能够获取锁执行任务。 在实际项目中,可以结合Spring的定时任务功能,将上述代码作为一个定时任务执行逻辑。这样就可以实现定时任务在分布式环境中的不重复执行。 希望以上内容对您有帮助! ### 回答3: Redission是一个基于Redis的分布式Java框架,可用于解决分布式系统中的各种问题,包括分布式锁。要使用Redission解决定时任务重复执行问题,可以按照以下步骤进行操作: 1. 引入Redission依赖:在项目的pom.xml文件中添加Redission的依赖,确保项目可以使用Redission相关的类和方法。 2. 创建Redission客户端:使用Redission提供的配置信息,创建一个Redission客户端对象,并与Redis实例建立连接。 3. 获取分布式锁:在每个定时任务开始执行前,通过调用Redission的分布式锁方法获取锁。 4. 判断锁的状态:在获取锁成功后,在定时任务的代码中加入判断锁的逻辑,确保只有第一个获取到锁的任务可以继续执行,其他任务则放弃执行并等待下次定时。 5. 释放锁:在定时任务执行完成后,调用Redission的释放锁方法,释放之前获取的锁资源,以便其他任务可以获取到锁并执行。 通过以上步骤,使用Redission可以实现分布式锁,确保定时任务不会被重复执行。需要注意的是,在使用分布式锁时,应该关注锁的超时时间,以避免某个任务异常退出或崩溃导致锁一直占用而无法释放。另外,还要确保Redis的高可用性,以及Redission客户端与Redis实例之间的网络通信稳定性,以保证分布式锁的可靠性和正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值