0、寫在前面
最近在項目開發過程中,涉及到定時任務的編寫,定時任務大家都知道,在多服務器部署時,爲了防止同一時間同一任務多次執行的問題,通常需要使用分佈式定時任務進行處理,這部分對應的框架也很多,例如:xxl-job,power-job,elastic-job,但是由於考慮到當前所負責開發的項目體量,感覺使用上面所提到的分佈式定時任務框架太過於繁重,所以,這裏就使用了spring提供的scheduler定時任務註解方式開發,雖然此種方式開發簡便,但是同一時間同一任務多次執行的問題還是存在的,因此爲了解決此問題,這裏便引入了shedlock鎖組件。
關於shedlock,這裏機翻了官網的一段說明,僅供簡單介紹,詳細可參看官網介紹(官網地址:https://github.com/lukas-krecan/ShedLock
1、版本說明
Spring Cloud Alibaba版本:2022.0.0.0-RC1
Springboot版本:3.0.0
jdk版本:17.0.6
ShedLock版本:5.3.0
mysql版本:8.0.30
2、ShedLock使用
由於項目使用的數據庫爲MySQL數據庫,所以這裏使用了shedlock-jdbcTemplate方式,關於其他存儲方式的使用可以參看官網(官網地址:https://github.com/lukas-krecan/ShedLock)
2.1、創建數據庫
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL COMMENT '鎖名稱',
lock_until TIMESTAMP(3) NOT NULL COMMENT '釋放鎖時間',
locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '獲取鎖時間',
locked_by VARCHAR(255) NOT NULL COMMENT '鎖提供者',
PRIMARY KEY (name)
);
官網說明:
<properties>
<shedlock.version>5.3.0</shedlock.version>
</properties>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-core</artifactId>
<version>${shedlock.version}</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>${shedlock.version}</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>${shedlock.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-jdbc</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.6</version>
</dependency>
說明:
由於Springboot 3.0.0版本使用的Spring 6.0.2版本在針對數據表中存在數據插入時,會報Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException異常(issue地址:https://github.com/spring-projects/spring-framework/issues/29511),導致shedlock執行時,報類似異常,針對此問題,spring官方也進行了修復(https://github.com/spring-projects/spring-framework/releases/tag/v6.0.3),但是由於項目依賴管理的父pom定義了spring的版本,這裏不方便修改父pom的依賴信息,所以就在項目中單獨添加了spring-jdbc的依賴,已解決此異常。異常信息如下:
Spring官方修復信息:
@Configuration
public class SchedulerLockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.build()
);
}
}
2.4、啓動類配置
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
...
@Scheduled(cron = "0 */2 * * * ?")
@SchedulerLock(name = "scheduledTaskName", lockAtLeastFor = "PT60S", lockAtMostFor = "PT60S")
@Transactional(rollbackFor = Exception.class)
public void scheduledTask() {
// 代碼省略......
}
shedlock數據表數據:
2.6、註解說明
@SchedulerLock:
關於lockAtLeastFor、lockAtMostFor屬性說明:
當第一個微服務執行定時任務的時候,會將此定時任務進行鎖操作,然後其他的定時任務就不會再執行,鎖操作有一定的時長,超過這個時長以後,鎖釋放,然後所有的定時任務進行爭搶下一個定時任務的執行權利,如此循環。其中兩個配置lockAtMostFor和lockAtLeastFor,保證了在一個定時任務的區間內只有一個定時任務在執行,同時也保證了即便是其中的一個定時任務掛掉了,到一定的時間以後,鎖也會釋放,其他的定時任務依舊會進行執行權的爭奪,執行定時任務。