Dirección original: https://blog.csdn.net/qq_32182637/article/details/111871188
https://blog.csdn.net/qq_35913663/article/details/124910631
escrito en frente
Este artículo es solo un registro y resumen de mi propia práctica después de referirme a otros artículos recientes.Todavía hay muchas deficiencias en la escena y los detalles, que necesitan ser complementados y corregidos.
descripción general
ShedLock solo hace una cosa. Garantiza que las tareas programadas se ejecuten como máximo una vez a la vez. Si una tarea se ejecuta en un nodo, adquiere un bloqueo que impide la ejecución de la misma tarea desde otro nodo (o subproceso). Tenga en cuenta que si una tarea ya se ejecutó en un nodo, la ejecución en otros nodos no esperará, simplemente la omitirá.
Actualmente, se admiten tareas programadas de Spring coordinadas a través de Mongo, bases de datos JDBC, Redis, Hazelcast o ZooKeeper. Se esperan mecanismos de sincronización y coordinación adicionales en el futuro.
ShedLock necesita usar la anotación @SchedulerLock para implementar bloqueos para un método determinado. Los escenarios distribuidos son los escenarios principales y típicos para su aplicación, pero esto no significa que ShedLock solo se pueda usar en entornos distribuidos. Depende de su comprensión de su principios Cómo usarlo.
Breve análisis del principio ShedLock
El principio de ShedLock es muy simple. Primero observe la clase de anotación @SchedulerLock:
@Objetivo({TipoElemento.MÉTODO, TipoElemento.ANOTATION_TYPE})
@Retención(RetenciónPolicy.RUNTIME)
@interfaz pública SchedulerLock {
Cadena nombre() por defecto "";
long lockAtMostFor() por defecto -1L;
Cadena lockAtMostForString() por defecto "";
long lockAtLeastFor() por defecto -1L;
Cadena lockAtLeastForString() por defecto "";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
De acuerdo con la clase de anotación, podemos saber
Se puede usar en métodos (ElementType.METHOD), que es una forma común de anotación
Se puede usar en otras clases de anotación (ElementType.ANNOTATION_TYPE). No sé cómo aplicar esta situación. Lo probé brevemente, pero no tiene el efecto deseado.
El atributo de nombre indica el nombre del bloqueo, que distingue entre mayúsculas y minúsculas
lockAtMostFor toma el bloqueo durante más tiempo, en milisegundos
lockAtMostForString El tiempo más largo para ocupar el candado, tipo de carácter, "PT1S" significa 1 segundo, "PT1M" significa 1 minuto, si se establece al mismo tiempo que el atributo lockAtMostFor, prevalecerá lockAtMostFor
lockAtLeastFor El tiempo mínimo para ocupar la cerradura, en milisegundos
lockAtLeastForString El tiempo más corto de ocupación del candado, tipo de carácter, "PT1S" significa 1 segundo, "PT1M" significa 1 minuto, si se establece al mismo tiempo que el atributo lockAtLeastFor, prevalecerá lockAtLeastFor
La implementación de ShedLock se basa en el almacenamiento externo, incluidas las bases de datos convencionales, las cachés Redis, etc.
Nombre de campo Descripción
nombre El nombre del bloqueo, valor único, mayúsculas y minúsculas
lock_until La hora de finalización de la ocupación del bloqueo =locked_at +lockAtMostFor
bloqueado_at comienza a ocupar el tiempo de bloqueo
bloqueado_por ocupante, generalmente nombre de host
Al observar el código fuente, se puede encontrar que cuando se necesita adquirir un bloqueo, intentará insertar un registro en la tabla de shedlock y el nombre se usa como clave principal. Si no hay un bloqueo con el mismo nombre, el se insertará el registro y la cerradura se ocupará con éxito
INSERTAR EN shedlock(nombre, bloquear_hasta, bloqueado_en, bloqueado_por) VALORES(?, ?, ?, ?)
1
Si ya existe un bloqueo con el mismo nombre, se violará la restricción única de la clave principal y la inserción fallará. En este momento, intentará filtrar los registros con el mismo nombre de bloqueo en la tabla de bloqueo y tendrá sido liberado (bloqueo_hasta<hora actual). Si hay registros que cumplen con las condiciones, actualice el registro de registros y ocupó con éxito el bloqueo
ACTUALIZAR shedlock SET lock_until =?,locked_at=?,locked_by=? DONDE nombre = ? Y lock_until <= ?
1
Si no se pueden filtrar registros elegibles, significa que la adquisición del bloqueo ha fallado y se abandonará la tarea de ejecución.
Una vez completada la ejecución del método de tarea, si el tiempo actual no ha excedido el tiempo lock_until, el tiempo lock_until del registro actualizado está bloqueado_en+bloquearAlMenosPor, es decir, la duración de ocupar el bloqueo se cambia a la duración mínima
Además, debe tenerse en cuenta que ShedLock es un mecanismo de bloqueo basado en el tiempo. En un escenario distribuido, si se implementan diferentes nodos en diferentes hosts, el tiempo del host se utilizará de forma predeterminada. En este momento, es necesario enfatizar la sincronización de tiempo entre los hosts. Por supuesto, en la versión superior del paquete de dependencia, proporcionará el tiempo del host para configurar el almacenamiento externo, como el tiempo del host de la base de datos
Para obtener más detalles, consulte otro artículo "Principio de bloqueo distribuido de SchedulerLock"
ShedLock+Mysql
Primero necesitas importar dependencias
<!--Esta dependencia es el paquete de dependencia central de shedlock, que está en contacto con Spring y, a veces, la versión incorrecta hará que falle-->
<dependencia>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>cobertizo-resorte</artifactId>
<versión>2.2.0</versión>
</dependencia>
<!--Requerido para acceder a la base de datos-->
<dependencia>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<versión>2.2.0</versión>
</dependencia>
1
2
3
4
5
6
7
8
9
10
11
12
Crear tablas de base de datos
CREAR TABLA cobertizo (
nombre varchar (64) COLLATE utf8mb4_bin NO NULO,
lock_until timestamp(3) NO NULO,
bloqueado_en marca de tiempo (3) NO NULO PREDETERMINADO CURRENT_TIMESTAMP (3),
bloqueado_por varchar (255) COLLATE utf8mb4_bin NO NULO,
CLAVE PRINCIPAL (nombre)
) MOTOR = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin;
1
2
3
4
5
6
7
Implementar una clase de configuración para proporcionar un LockProvider
importar net.javacrumbs.shedlock.core.LockProvider;
importar net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
importar org.springframework.context.annotation.Bean;
importar org.springframework.context.annotation.Configuration;
importar org.springframework.jdbc.core.JdbcTemplate;
importar org.springframework.scheduling.annotation.EnableScheduling;
importar javax.sql.DataSource;
import static net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider.Configuration.builder;
@Configuración
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
Configuración del programador de clase pública {
@Frijol
lockProvider public LockProvider(fuente de datos fuente de datos) {
//Puede personalizar la fuente de datos, lo que puede considerarse una consideración, y generalmente no usa esto
org.apache.tomcat.jdbc.pool.DataSource dataSource1 = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource1.setUrl("jdbc:mysql://127.0.0.1:3601/ICSP?useUnicode=true&characterEncoding=utf8&useSSL=false");
fuente de datos1.setUsername("tom");
fuente de datos1.setPassword("tommy");
LockProvider lockProvider= new JdbcTemplateLockProvider(constructor()
//Especifique el nombre de la tabla
.withTableName("cobertizo")
//Especifique la fuente de datos, generalmente use dataSource en lugar de la fuente de datos definida manualmente
.withJdbcTemplate(nueva JdbcTemplate(fuente de datos1))
//Especifique el nombre del campo de la tabla, la cantidad de campos es fija, solo se puede cambiar el nombre y solo la versión superior de la dependencia shedlock-provider-jdbc-template proporciona este elemento de configuración
// .withColumnNames(new JdbcTemplateLockProvider.ColumnNames("nombre","bloquear_hasta","bloqueado_en","bloqueado_por"))
//Utilice la hora de la base de datos, solo la versión superior de la dependencia shedlock-provider-jdbc-template proporciona este elemento de configuración
// .usandoDbTime()
//La función es desconocida, solo la dependencia de versión superior shedlock-provider-jdbc-template proporciona este elemento de configuración
// .withLockedByValue("mivalor")
//La función es desconocida, solo la dependencia de versión superior shedlock-provider-jdbc-template proporciona este elemento de configuración
// .conNivelDeAislamiento(1)
.construir());
return proveedorcerradura;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dieciséis
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Con respecto a la configuración anterior, se necesitan algunas instrucciones complementarias:
@EnableScheduling debe agregarse solo cuando se usan tareas programadas, que también es el escenario de aplicación más típico de shedlock
La anotación @EnableSchedulerLock elimina la posibilidad de establecer el tiempo más largo y más corto predeterminado para ocupar la cerradura.También hay un parámetro de modo, y los valores que se pueden configurar son:
descripción del valor
EnableSchedulerLock.InterceptMode.PROXY_SCHEDULER se usa con @Scheduled
EnableSchedulerLock.InterceptMode.PROXY_METHOD se usa solo en el método, lo que significa que siempre que se llame al método, intentará ocupar el bloqueo, que es otro escenario de uso de shedlock
La versión Shedlock-provider-jdbc-template agrega la comparación del método JdbcTemplateLockProvider.Configuration.builder
Método Agregar versión
4.1.0 .con nombres de columna
.withLockedByValue
4.9.0 .usandoDbTime
4.27.0 .con nivel de aislamiento
4. Si usa una versión superior dependiente de shedlock-provider-jdbc-template, también debe usar una versión superior de la versión dependiente de shedlock-spring, de lo contrario, se informará un error durante la ejecución. Y si se usa una versión más alta de dependencia de shedlock-spring, es posible que también deba coincidir con la versión de dependencia del contexto de spring (solo una suposición, qué dependencia no se ha confirmado). version hará que al registrar una Tarea, la tarea no se configure como LockabaleRunable, sino como ScheduledMethodRunable ordinario, el impacto directo es que el shedlock de la tarea programada fallará.
Acabo de encontrar un problema aquí, pero no sé cómo resolverlo. Si sabe que desea usar shedlock-provider-jdbc-template versión 4.27.0 y superior, puede usar otros paquetes dependientes. Bienvenido informar
Luego puede usar la anotación @SchedulerLock
ShedLock+Redis
1. archivo pom
Redis debe tener:
<dependencia>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependencia>
artículos requeridos shedlock:
<dependencia>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>cobertizo-resorte</artifactId>
<versión>4.19.1</versión>
</dependencia>
Opciones de Shedlock (aquí se usa redis, también se pueden usar otras bases de datos, consulte el sitio web oficial https://github.com/lukas-krecan/ShedLock para obtener más detalles):
<dependencia>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<versión>2.5.0</versión>
</dependencia>
————————————————
@Configuración
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
clase pública ShedLockConfig {
@Recurso
RedisTemplate<Cadena, Objeto> redisTemplate;
@Frijol
proveedor de bloqueo público proveedor de bloqueo () {
devolver nuevo RedisLockProvider(redisTemplate.getConnectionFactory());
}
}
@Slf4j
@Componente
Clase pública TaskRun {
@Programado(cron = "0 0 */1 * *?")
@SchedulerLock(nombre = "fylr")
fylr vacío público () {
System.out.println("ejecutar...");
}
}
ShedLock+Mongo
Para ser agregado
Bloqueo de cobertizo+Guardián del zoológico
Para ser agregado
————————————————
Declaración de derechos de autor: este artículo es un artículo original del bloguero de CSDN "Zhao Jiaen", siguiendo el acuerdo de derechos de autor CC 4.0 BY-SA. Adjunte el enlace de la fuente original y esta declaración para su reimpresión.
Enlace original: https://blog.csdn.net/qq_35913663/article/details/124910631