java分布式系统定时任务,如何保证多台服务只执行一次

新建一张临时表,当执行定时器的时候去表里查看是是否今天执行过任务。

执行完毕后修改状态,所以其他的表来修改的时候去来确认任务是否执行

一、代码

	private static String serverIp = null;
 
    static {
        //获取服务器的IP地址,便于后续追踪
        try {
            InetAddress address = InetAddress.getLocalHost();
            serverIp = address.getHostAddress();
        } catch (Exception e) {
            logger.error("获取服务器IP地址有误!!");
            e.printStackTrace();
        }
    }
 
    /**
     * 每日凌晨1点执行
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void xxxSchedule(){
        logger.info("job start");
        String jobName = "xxx";
        long startTime = new Date().getTime();
        try {
            if (canExecute(jobName)){
                jobMapper.xxxSchedule();
                jobMapper.updateJobStatus(jobName,serverIp,"off");
                logger.info(jobName+"执行完成,耗时:"+(new Date().getTime()-startTime)+"毫秒!");
            }
        } catch (Exception e) { 
            e.printStackTrace(); 
        }
    }
 
 
    private Boolean canExecute(String jobName) throws Exception {
        int max = 10000;
        int min = (int) Math.round(Math.random()*8000);
        long sleepTime = Math.round(Math.random()*(max-min));
        logger.info(jobName+"睡了:"+ sleepTime + "毫秒");
        Thread.sleep(sleepTime);
 
        if (jobMapper.getJobOff(jobName) == 1){
            jobMapper.updateJobStatus(jobName,serverIp,"on");
            return true;
        }
        logger.info(jobName+"已被其他服务器执行");
        return false;
    }

二、数据库表

CREATE TABLE `job_manager` (
  `job_name` varchar(50) NOT NULL PRIMARY KEY COMMENT '名称',
  `job_desc` varchar(50)  COMMENT 'job描述',
  `server_ip` varchar(50) NOT NULL COMMENT '服务器ip',
  `on_off` varchar(10) DEFAULT 'off' COMMENT '开关(on:正在执行,off:执行完毕)',
  `update_date` datetime NOT NULL COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job管理' ROW_FORMAT=DYNAMIC;
 
 
INSERT INTO `job_manager`
VALUES
('xxx','更新xxx的job','0.0.0.0','off',now());

三、查询或改状态的sql

如下sql中:on_off = 'off' AND update_date < curdate(),是可执行job的标志

<select id="getJobOff" parameterType="string" resultType="int">
        SELECT count(1) FROM job_manager
        WHERE job_name = #{jobName} AND on_off = 'off' AND update_date < curdate()
    </select>
 
    <update id="updateJobStatus" parameterType="map">
        UPDATE job_manager
        SET on_off=#{status},server_ip=#{serverIp},update_date=now()
        WHERE job_name = #{jobName}
    </update>

猜你喜欢

转载自blog.csdn.net/bigwatermel/article/details/82730679