主要架构选型

Springboot(2.2.2)+Mybatis-Plus(3.0-RC3)+shedLock(4.0.1)

开发注意事项

Q&A

  • 1、 ShedLock 部署时需要创建表 (特别注意不同库创建的sql)

    Mysql:
    CREATE TABLE shedlock(
          name VARCHAR(64), 
          lock_until TIMESTAMP(3) NULL, 
          locked_at TIMESTAMP(3) NULL, 
          locked_by  VARCHAR(255), 
          PRIMARY KEY (name)
      ) 
    
    Oracel:
    DROP TABLE ICC_UNION.SHEDLOCK CASCADE CONSTRAINTS;
    CREATE TABLE SHEDLOCK (
     name VARCHAR2(64 CHAR),
     lock_until TIMESTAMP,
     locked_at TIMESTAMP,
     locked_by  VARCHAR2(255 CHAR),
     PRIMARY KEY (name)
    );

    @SchedulerLock(name = "任务名称 不要重复", lockAtMostFor = "见下", lockAtLeastFor ="见下")

    /**
     *You can also set lockAtMostFor attribute which specifies how long the lock should be kept in case the executing node dies.
     *  This is just a fallback, under normal circumstances the lock is released as soon the tasks finishes.
     *  You have to set lockAtMostFor to a value which is much longer than normal execution time.
     *  If the task takes longer than lockAtMostFor the resulting behavior may be unpredictable
     *  (more then one process will effectively hold the lock).
     *  lockAtMostFor:锁的最大时间单位为毫秒
     *
     *Lastly, you can set lockAtLeastFor attribute which specifies minimum amount of time for which the lock should be kept.
     *  Its main purpose is to prevent execution from multiple nodes in case of really short tasks and clock difference between the nodes.
     *  lockAtLeastFor:锁的最小时间单位为毫秒
     */

项目ShedLock地址

pom主要jar引用


 
            com.oracle
            ojdbc6
            11.2.0.3
        
        
            com.alibaba
            druid-spring-boot-starter
            1.1.10
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.0-RC3
        
        
            com.zaxxer
            HikariCP
            3.2.0
        
        
            org.projectlombok
            lombok
            1.16.14
            provided
        
        
            com.spring4all
            swagger-spring-boot-starter
            1.6.0.RELEASE
            compile
        

        
            net.javacrumbs.shedlock
            shedlock-spring
            4.0.1
        
        
            net.javacrumbs.shedlock
            shedlock-provider-jdbc-template
            4.0.1
        

SchedLockConfig 主要配置

import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.sql.DataSource;

/**
 * @author nopsmile
 * defaultLockAtMostFor 指定在执行节点结束时应保留锁的默认时间使用ISO8601 Duration格式
 * 作用就是在被加锁的节点挂了时,无法释放锁,造成其他节点无法进行下一任务
 * 这里默认30s
 * 关于ISO8601 Duration格式用的不到,具体可上网查询下相关资料,应该就是一套规范,规定一些时间表达方式
 */
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "30s")
public  class SchedLockConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }

}

mybatis主要配置


import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.util.Properties;
/**
 * @author nopsmile
 */
@Configuration
@EnableTransactionManagement
@ComponentScan
//@MapperScan("com.itcc.mva.mapper*")
public class MybatisPlusConfig {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
    /**
     * 打印 sql
     */
    @Bean
    @Profile({"test"})// 设置 test 环境开启
    public PerformanceInterceptor performanceInterceptor() {
        logger.info("loading the config of MybatisPlusConfig");
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        //格式化sql语句
        Properties properties = new Properties();
        properties.setProperty("format", "true");
        performanceInterceptor.setProperties(properties);
        return performanceInterceptor;
    }
}

其中job类的

@Component
public class demoJob {
@Scheduled(cron = "0/5 * * * * ?")
    @SchedulerLock(name = "demoJobName", lockAtMostFor = "3s", lockAtLeastFor = "3s")
    public void pushInfo() {
        ...
        }

}

启动类

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@MapperScan("com.mapper")
@SpringBootApplication
public class MvaApplication {

    public static void main(String[] args) {
        SpringApplication.run(MvaApplication.class, args);
    }

}

至此整合完毕。
本案例适用于小型分布式定时任务,不想用框架的。
注意:
多节点需要时间同步,否则会出现任务重复执行问题。