当前位置: 首页 > news >正文

springboot基础(82):分布式定时任务解决方案shedlock

文章目录

  • 前言
  • 简介
  • shedlock + db
    • SchedulerLock注解说明
  • shedlock + redis
  • 遇到的问题
    • 1.配置shedlock不生效
    • 2.报错net/javacrumbs/shedlock/core/LockProvider
  • shedlock升级高版本
  • 同名定时任务

前言

多节点或者多服务器拥有相同的定时任务,这种情况下,不同节点的相同定时任务会被重复执行。如何解决分布式定时任务重复执行问题?此刻我们可以引入分布式定时任务解决shedlock来解决这种定时任务重复执行的问题。

代码已分享至Gitee: https://gitee.com/lengcz/shedlock01

简介

Shedlock是一个基于Java的分布式锁库,用于解决分布式环境下的并发问题。它可以确保同一时间只有一个线程能够获取到锁,从而避免了多线程竞争导致的数据不一致或错误的问题。

Shedlock的原理是在数据库中创建一个特殊的表,用于记录锁的状态和持有者信息。当一个线程想要获取锁时,它会在表中插入一条记录,如果插入成功,则表示该线程成功获取到了锁;否则,表示有其他线程已经获取到了锁,当前线程需要等待。

Shedlock提供了简单易用的API,可以方便地在代码中使用锁。它支持不同的锁提供者,包括数据库(如MySQL、PostgreSQL)、ZooKeeper等。此外,Shedlock还提供了一些高级特性,如自动解锁、锁超时、定时任务等,以满足不同的场景需求。

总的来说,Shedlock是一个可靠、高效的分布式锁库,可以帮助开发者在分布式环境中处理并发问题,保证数据的一致性和正确性。它的设计简单,易于集成和使用,是Java开发者的理想选择之一。

shedlock + db

  1. 创建表
CREATE TABLE `shedlock` (`name` varchar(64) COLLATE utf8mb4_bin NOT NULL,`lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),`locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),`locked_by` varchar(255) COLLATE utf8mb4_bin NOT NULL,PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
  1. 引入依赖
<!--此依赖是shedlock核心依赖包,编译时依赖spring,大版本需要一致--><dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-spring</artifactId><version>2.2.0</version></dependency><!--shedlock+jdbc 方案需要引入此依赖--><dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-provider-jdbc-template</artifactId><version>2.2.0</version></dependency><!--quartz定时任务--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><!--mysql连接驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--jdbcTemplate需要的依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>
  1. 配置数据源(如果没有配置的话)
spring:datasource:url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/db1?characterEncoding=UTF-8&useSSL=false   #//username: root    #//password: 123456   #//driver-class-name: com.mysql.cj.jdbc.Driver
  1. 配置LockProvider

import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;import javax.sql.DataSource;import static net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider.Configuration.builder;@Configuration
@EnableScheduling  //开启定时任务
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S") //默认锁的最大占有30秒,建议在启动类上添加,这里是为了方便
public class SchedulerConfiguration {@AutowiredDataSource dataSource;@Beanpublic LockProvider lockProvider() {//        //可以自定义数据源,可以作为一种考虑,一般不使用这个
//        org.apache.tomcat.jdbc.pool.DataSource dataSource1 = new org.apache.tomcat.jdbc.pool.DataSource();
//        dataSource1.setUrl("jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false");
//        dataSource1.setUsername("root");
//        dataSource1.setPassword("123456");LockProvider lockProvider = new JdbcTemplateLockProvider(builder()//指定表名.withTableName("shedlock")//指定数据源,一般使用dataSource而非手动定义的数据源.withJdbcTemplate(new JdbcTemplate(dataSource))//指定表字段名称,字段数量固定,只能改名称,且只有较高版本的shedlock-provider-jdbc-template依赖才提供该配置项
//                .withColumnNames(new JdbcTemplateLockProvider.ColumnNames("name","lock_until","locked_at","locked_by"))//使用数据库时间,只有较高版本的shedlock-provider-jdbc-template依赖才提供该配置项
//                .usingDbTime()//作用未知,只有较高版本的shedlock-provider-jdbc-template依赖才提供该配置项
//                .withLockedByValue("myvalue")//作用未知,只有较高版本的shedlock-provider-jdbc-template依赖才提供该配置项
//                .withIsolationLevel(1).build());return lockProvider;}
}
  1. 使用
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Slf4j
@Component
@EnableScheduling //开启定时任务
public class MyJob {@Scheduled(cron = "0,15,30,45 * * * * ?")@SchedulerLock(name = "task1", lockAtLeastForString = "PT5S", lockAtMostForString = "PT10S")public void task1() {log.info("-----task1-------");}
}    

定时任务执行后,查看数据库

在这里插入图片描述

  • name : 定时任务名称,多节点执行定时任务,谁获得锁资源谁执行
  • locked_at: 上锁开始时间,就是任务的执行开始时间
  • lock_until: 释放锁的时间
  • locked_by: 谁操作的,通常会计算机名称

SchedulerLock注解说明

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SchedulerLock {/*** 任务的名称,同名任务互斥,只会执行一个*/String name() default "";/***  锁的最多占用多久,单位毫秒*/long lockAtMostFor() default -1L;/*** 锁的最多占用多久,字符格式,PT2S 表示2秒,PT2M表示2分钟*/String lockAtMostForString() default "";/*** 锁的最少占用时间,单位毫秒*/long lockAtLeastFor() default -1L;/*** 锁的最少占用时间,字符格式,PT2S 表示2秒,PT2M表示2分钟*/String lockAtLeastForString() default "";
}

shedlock + redis

引入依赖,注意建议版本相同,避免可能带来的版本兼容问题。

  1. 引入依赖
 <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-redis-spring</artifactId><version>2.2.0</version></dependency>
  1. 配置LockProvider
    @Beanpublic LockProvider lockProvider(RedisTemplate redisTemplate) {return new RedisLockProvider(redisTemplate.getConnectionFactory());}

遇到的问题

1.配置shedlock不生效

  • 在非springboot中,请确保配置的bean是否被扫描到,确保LockProvider是否被加载到容器中。
  • 是否定时任务开启了线程池等

2.报错net/javacrumbs/shedlock/core/LockProvider

请检查shedlock-spring 依赖的spring版本与项目的spring版本是否一致(大版本号是否一致)。

在这里插入图片描述
报错net/javacrumbs/shedlock/core/LockProvider

注意 shedlock改版本后,注意检查代码,会存在轻微不同。

shedlock升级高版本

升级到4.46.0后,SchedulerLock会提示废弃
在这里插入图片描述
此时需要更换导入新的SchedulerLock注解

import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;

该注解的内容,只有3个参数,lockAtMostFor 锁的最长占有时间,lockAtLeastFor 锁的最小占有时间,单位毫秒
在这里插入图片描述
代码

    @Scheduled(cron = "0,15,30,45 * * * * ?")@SchedulerLock(name = "task1", lockAtLeastFor = "PT5S", lockAtMostFor = "PT10S")public void task1() {log.info("-----task1-------");}

同名定时任务

同名定时任务只会执行一个,多个节点(节点这里指的是服务,一个服务视为一个节点)相同名称的任务只会有一个获取到锁资源并执行,而同一个节点的同名任务只会有一个被执行,且任务的执行是随机的,没有规律,不能预测下一次谁有执行资格,对于多节点而言,也同样遵循此规则。
在这里插入图片描述

相关文章:

springboot基础(82):分布式定时任务解决方案shedlock

文章目录 前言简介shedlock dbSchedulerLock注解说明 shedlock redis遇到的问题1.配置shedlock不生效2.报错net/javacrumbs/shedlock/core/LockProvider shedlock升级高版本同名定时任务 前言 多节点或者多服务器拥有相同的定时任务&#xff0c;这种情况下&#xff0c;不同节…...

【Golang】Gorm乐观锁optimisticlock的使用

在数据库操作中&#xff0c;为了保证数据的一致性和完整性&#xff0c;常常需要采取一些措施来防止并发操作导致的数据冲突。悲观锁和乐观锁是两种常见的并发控制机制。 悲观锁&#xff08;Pessimistic Lock&#xff09; 悲观锁的基本假设是&#xff0c;数据在并发访问时很可能…...

Apache Doris 发展历程、技术特性及云原生时代的未来规划

本文节选自《基础软件之路&#xff1a;企业级实践及开源之路》一书&#xff0c;该书集结了中国几乎所有主流基础软件企业的实践案例&#xff0c;由 28 位知名专家共同编写&#xff0c;系统剖析了基础软件发展趋势、四大基础软件&#xff08;数据库、操作系统、编程语言与中间件…...

2024-02-26(Spark,kafka)

1.Spark SQL是Spark的一个模块&#xff0c;用于处理海量结构化数据 限定&#xff1a;结构化数据处理 RDD的数据开发中&#xff0c;结构化&#xff0c;非结构化&#xff0c;半结构化数据都能处理。 2.为什么要学习SparkSQL SparkSQL是非常成熟的海量结构化数据处理框架。 学…...

RubyMine 2023:让Ruby编程变得更简单 mac/win版

JetBrains RubyMine 2023是一款专为Ruby开发者打造的强大集成开发环境&#xff08;IDE&#xff09;。这款工具集成了许多先进的功能&#xff0c;旨在提高Ruby编程的效率和生产力。 RubyMine 2023软件获取 RubyMine 2023的智能代码编辑器提供了丰富的代码补全和提示功能&#…...

低功耗设计——门控时钟

1. 前言 芯片功耗组成中&#xff0c;有高达40%甚至更多是由时钟树消耗掉的。这个结果的原因也很直观&#xff0c;因为这些时钟树在系统中具有最高的切换频率&#xff0c;而且有很多时钟buffer&#xff0c;而且为了最小化时钟延时&#xff0c;它们通常具有很高的驱动强度。此外&…...

《凤凰架构》-本地事务章节 读书笔记

1、写锁又名排它锁&#xff0c;写锁禁止其他事务施加读锁和写锁&#xff0c;而不禁止其他事务读取数据&#xff08;如果遇到了个不加任何锁的另一个事务2&#xff0c;写锁是无法阻止事务2读取数据的&#xff09;&#xff0c;这就是读未提交隔离级别中的脏读问题产生的根因。 2…...

ruby对比python,30分钟教程

会python还需要搞会ruby吗&#xff1f; web方面&#xff1a;ruby有rails&#xff0c;python有flask,django&#xff0c;rails远超django Ruby&#xff0c;一种简单快捷的面向对象&#xff08;面向对象程序设计&#xff09;脚本语言&#xff0c;在20世纪90年代由日本人松本行弘…...

C语言——oj刷题——判断闰年

当我们谈到判断闰年时&#xff0c;我们通常会遵循以下规则&#xff1a;闰年是指能被4整除但不能被100整除的年份&#xff0c;或者能被400整除的年份。在C语言中&#xff0c;我们可以通过编写一个简单的程序来实现这一功能。下面是一个示例代码&#xff0c;用于判断一个给定年份…...

Git笔记——3

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、合并模式和分支策略 二、bug分支 三、强制删除分支 四、创建远程仓库 五、克隆远程仓库_HTTPS和_SSH 克隆远程仓库_HTTPS 克隆远程仓库_SSH 六、向远程仓库…...

C++面试 -操作系统-安全能力:死锁的危害、出现原因、解决方法

目录 死锁的危害 死锁出现的原因 死锁的解决方法 死锁是计算机科学中一个非常重要的概念&#xff0c;特别是在多线程、并发编程以及数据库管理系统等领域中。下面是关于死锁的危害、出现原因和解决方法的基础概述&#xff1a; 死锁的危害 资源浪费&#xff1a;死锁导致系统…...

台湾香港澳门媒体宣发稿报道有哪些平台资源,跨境出海推广新闻营销公司告诉你

【本篇由言同数字科技有限公司原创】随着全球化的快速发展和互联网的普及&#xff0c;品牌越来越重视海外市场的开拓。作为亚洲地区的重要经济中心&#xff0c;香港、台湾和澳门不仅具有独特的地理位置和文化背景&#xff0c;还拥有丰富的媒体资源。在本文中&#xff0c;我们将…...

Python分支和循环结构及其应用(文末送书)

一、分支结构 应用场景 我们写的Python代码都是一条一条语句顺序执行&#xff0c;这种代码结构通常称之为顺序结构。然而仅有顺序结构并不能解决所有的问题。 if语句的使用 在Python中&#xff0c;要构造分支结构可以使用if、elif和else关键字。所谓关键字就是有特殊含义的…...

机器学习——线性代数中矩阵和向量的基本介绍

矩阵和向量的基本概念 矩阵的基本概念&#xff08;这里不多说&#xff0c;应该都知道&#xff09; 而向量就是一个特殊的矩阵&#xff0c;即向量只有一列&#xff0c;是个n*1的矩阵 注&#xff1a;一般矩阵用大写字母表示&#xff0c;向量用小写字母表示 矩阵的加减运算 两个…...

基于R语言的Meta分析【全流程、不确定性分析】方法与Meta机器学习技术应用

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…...

蜘蛛蜂优化算法SWO求解不闭合MD-MTSP,可以修改旅行商个数及起点(提供MATLAB代码)

1、蜘蛛蜂优化算法SWO 蜘蛛蜂优化算法&#xff08;Spider wasp optimizer&#xff0c;SWO&#xff09;由Mohamed Abdel-Basset等人于2023年提出&#xff0c;该算法模型雌性蜘蛛蜂的狩猎、筑巢和交配行为&#xff0c;具有搜索速度快&#xff0c;求解精度高的优势。VRPTW&#x…...

Java架构师之路六、高并发与性能优化:高并发编程、性能调优、线程池、NIO、Netty、高性能数据库等。

目录 高并发编程&#xff1a; 性能调优&#xff1a; 线程池&#xff1a; NIO&#xff1a; Netty&#xff1a; 高性能数据库&#xff1a; 上篇&#xff1a;Java架构师之路五、微服务&#xff1a;微服务架构、服务注册与发现、服务治理、服务监控、容器化等。-CSDN博客 下篇…...

MySQL-行转列,链接查询

1. 行转列 1.1 示例数据准备 create table test_9(id int,name varchar(22),course varchar(22),score decimal(18,2) ); insert into test_9 (id,name,course,score)values(1,小王,java,99); insert into test_9 (id,name,course,score)values(2,小张,java,89.2); inse…...

Linux之安装jdk,tomcat,mysql,部署项目

目录 一、操作流程 1.1安装jdk 1.2安装tomcat&#xff08;加创建自启动脚本&#xff09; 1.3 安装mysql 1.4部署项目 一、操作流程 首先把需要用的包放进opt文件下 1.1安装jdk 把jdk解压到/usr/local/java里 在刚刚放解压包的文件夹打开vim /etc/profile编辑器&#xff0c…...

HTMLElement.click()的回调触发踩坑

先看看以下代码 const el document.getElementById("btn") el.addEventListener("click", () > {Promise.resolve().then(() > console.log("microtask 1"));console.log("1"); }); el.addEventListener("click", (…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...