江宁网站建设公司,卡片式网站模板,安庆网站建设推广,台州建设信息港网站文章目录 前言简介shedlock dbSchedulerLock注解说明 shedlock redis遇到的问题1.配置shedlock不生效2.报错net/javacrumbs/shedlock/core/LockProvider shedlock升级高版本同名定时任务 前言
多节点或者多服务器拥有相同的定时任务#xff0c;这种情况下#xff0c;不同节… 文章目录 前言简介shedlock dbSchedulerLock注解说明 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
创建表
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)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_bin;引入依赖
!--此依赖是shedlock核心依赖包编译时依赖spring,大版本需要一致--dependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-spring/artifactIdversion2.2.0/version/dependency!--shedlockjdbc 方案需要引入此依赖--dependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-provider-jdbc-template/artifactIdversion2.2.0/version/dependency!--quartz定时任务--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-quartz/artifactId/dependency!--mysql连接驱动--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency!--jdbcTemplate需要的依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependency配置数据源(如果没有配置的话)
spring:datasource:url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/db1?characterEncodingUTF-8useSSLfalse #//username: root #//password: 123456 #//driver-class-name: com.mysql.cj.jdbc.Driver
配置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?useUnicodetruecharacterEncodingutf8useSSLfalse);
// 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;}
}使用
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
引入依赖注意建议版本相同避免可能带来的版本兼容问题。
引入依赖 dependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-spring/artifactIdversion2.2.0/version/dependencydependencygroupIdnet.javacrumbs.shedlock/groupIdartifactIdshedlock-provider-redis-spring/artifactIdversion2.2.0/version/dependency配置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-------);}同名定时任务
同名定时任务只会执行一个多个节点(节点这里指的是服务一个服务视为一个节点)相同名称的任务只会有一个获取到锁资源并执行而同一个节点的同名任务只会有一个被执行且任务的执行是随机的没有规律不能预测下一次谁有执行资格对于多节点而言也同样遵循此规则。