Java应用集群下的定时任务处理方案(mysql)

今天来说一个Java多机部署下定时任务的处理方案。

需求: 有两台服务器同时部署了同一套代码, 代码中写有spring自带的定时任务,但是每次执行定时任务时只需要一台机器去执行。

当拿到这个需求时我脑子中立马出现了两个简单的解决方案:

  • 利用ip进行判断, 两台机器ip肯定不一样, 指定某一台机器的ip运行。
  • 只在一台机器上部署定时任务的代码。

最后两个方案又都被自己否决了。 第一条,如果指定ip的机器出现了问题怎么办? 例如说宕机了, 那么该制定ip的机器上的定时任务是不是就无法运行了?如果以后该服务器迁移导致ip变化怎么办?
第二条, 同上, 还有就是要维护两套代码很不方便。

因为上面两个假设都不成立, 只能另找他法。 于是便想到利用mysql去解决, 之前了解过一点mysql的锁机制, 知道如果有同时的两个任务去写数据库中同一条记录, 只有一条会成功, 这是利用了mysql的排他锁。

下面就开始代码演示, 这里主要想给大家的是一个思路的提示, 代码还是很简单的。

  • 首先需要单独创建一张表

    CREATE TABLE `t_schedule_cluster` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '@cname:主键',
    `execute` int(1) NOT NULL COMMENT '@cname:执行状态',
    `version` int(11) NOT NULL COMMENT '@cname:版本号\r\n            ',
    `task_name` varchar(128) NOT NULL COMMENT '@cname:任务名称\r\n            ',
    `execute_ip` varchar(32) DEFAULT NULL COMMENT '@cname:执行ip\r\n            ',
    `update_time` datetime DEFAULT NULL COMMENT '@cname:修改时间\r\n            ',
    PRIMARY KEY (`id`),
    KEY `Index_series_id` (`execute`)
    ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='@cname:多机定时任务调度';

    看一下建成后的表结构, 注释写的已经很清楚了, 初始化时需要添加一些定时任务的名称(task_name), 这个要和你代码中保持一致, 后面会提到:
    Java应用集群下的定时任务处理方案(mysql)

  • 代码
    首先看下我代码中用到的spring定时任务:
    代码
    首先看下我代码中用到的spring定时任务:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns=
    xmlns:xsi=xmlns:task=xsi:schemaLocation=default-lazy-init="true">
    <description>使用Spring的 Scheduled的定时任务配置</description>
    <!--支持annotation的方式-->
    <task:annotation-driven  />
    <task:scheduler id="springScheduler"  pool-size="10"/>
    <task:scheduled-tasks scheduler="springScheduler"><!-- 测试使用, 项目启动后每隔一分钟执行一次 --><task:scheduled ref="listCarAction" method="listCar" cron="0 0/1 0 * * ?"/><task:scheduled ref="listCarAction" method="listCar" cron="0 0/1 0 * * ?"/>
    </task:scheduled-tasks>
    </beans>

    相信大家都是用过这种定时任务的设置方法, 因为它是spring自带的, 所以使用起来很方便, 这里我指定了两个定时任务来模拟两台机器的情况, 两个定时任务都是项目启动后每隔一分钟执行一次。

然后看看这个listCar中的代码:

//定时任务的名称, 这个和数据库中的task_name是保持一致的, 保证要执行该定时任务。
public static final String LIST_CAR_TASK = "listCarTask";
private ScheduleClusterTask scheduleClusterTask;
//这个时间是根据spring-scheduler.xml中配置的定时刷新时间, 比如说我们以后要设置这个定时任务时4小时刷新一次
public static final long maxExpireTime = 4 * 3600;public void listCar() {if (scheduleClusterTask.isValidMachine(maxExpireTime, CommonConstants.ScheduleTaskName.LIST_CAR_TASK)) {//执行具体的task方法, doTask();//将execute状态更新为0scheduleClusterTask.end(LIST_CAR_TASK);}}

最后看下最核心的代码:ScheduleClusterTask.java

/*** 多机定时任务工具类* Created by WangMeng on 2017/4/12.*/
@Service
public class ScheduleClusterTask {private ScheduleClusterEntityService scheduleClusterEntityService;/*** 这里因为两台机器都有同样的定时任务, 会同时执行这个方法,只有一台机器可以执行成功,返回true。* @param maxExpireTime 最大的检查时间。* @param taskName 任务名称。* @return*/public boolean isValidMachine(long maxExpireTime, String taskName) {boolean isValid = false;try {//通过taskName去数据库中查找到该条记录, 如果大家使用的是mybatis这里需要改一下, 就是一个简单的查询操作ScheduleClusterEntity carIndexEntity = scheduleClusterEntityService.findOne(ScheduleClusterEntity.Fields.taskName.eq(taskName));int execute = carIndexEntity.getExecute();String ip = InetAddress.getLocalHost().getHostAddress();long currentTimeMillis = System.currentTimeMillis();long time = carIndexEntity.getUpdateTime().getTime();if (execute == 0 && time + maxExpireTime - 1000 < currentTimeMillis) {isValid = checkMachine(taskName, carIndexEntity, ip);} else if (time + maxExpireTime - 1000 < currentTimeMillis){//这里要判断下, 如果上一次执行出现异常导致execute没有更新为0, 那么这里要判断上一次更新时间的间隔。isValid = checkMachine(taskName, carIndexEntity, ip);}} catch (UnknownHostException e) {e.printStackTrace();}return isValid;}/*** end方法主要是将excute(是否正在执行的标志位,0:没有执行, 1:正在执行)更新为0* @param taskName* @return*/public boolean end (String taskName) {ScheduleClusterEntity carIndexEntity = scheduleClusterEntityService.findOne(ScheduleClusterEntity.Fields.taskName.eq(taskName));//将execute状态更新为0return scheduleClusterEntityService.end(carIndexEntity);}private boolean checkMachine(String taskName, ScheduleClusterEntity carIndexRefresh, String ip) {return scheduleClusterEntityService.start(taskName, carIndexRefresh.getVersion(), ip);}@Autowiredpublic void setScheduleClusterEntityService(ScheduleClusterEntityService scheduleClusterEntityService) {this.scheduleClusterEntityService = scheduleClusterEntityService;}
}

这里还有start方法, 看看怎样的操作:

@Repository
public class DefaultScheduleClusterEntityDao extends AbstractDao<ScheduleClusterEntity> implements ScheduleClusterEntityDao {@Overridepublic boolean start(String taskName, int version, String ip) {String sql = "update t_schedule_cluster set execute = 1, " +"version = ?, execute_ip = ?, update_time = ?" +" where task_name = ? and version = ?";Sql s = new Sql(sql);s.addParam(version + 1);s.addParam(ip);s.addParam(SqlTimeUtils.nowTimestamp());s.addParam(taskName);s.addParam(version);return 1 == executeUpdate(s);}
}

核心的代码到了这里就没有了, 代码确实是非常非常的简单, 有兴趣的话大家可以在本地测试一下就可以。
当然还有更多很好地解决方案, 我这里秉承的是最简单的处理方式, 如果大家对我这个方案有疑问或者做的不好的地方都希望大家能够提出来, 谢谢了,

转载于:https://blog.51cto.com/14311648/2390405

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

概念验证_设置成功的UX概念验证

概念验证用户体验/概念证明/第1部分 (USER EXPERIENCE / PROOF OF CONCEPT / PART 1) This is the first article of a four-part series. Please read Part 2 and Part 3.这是由四个部分组成的系列文章的第一篇。 请阅读 第2 部分 和 第3部分 。 How do today’s top UX desi…

从 vue3 和 vite 源码中,我学到了一行代码统一规范团队包管理器的神器

1. 前言大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行四个月了&#xff0c;很多小伙伴表示收获颇丰。想学源码&#xff0c;极力推荐之前我写…

什么事接口

假设你设计一个和人交流的程序。 先建立一个接口 interface 人 //定义接口&#xff0c;它代表一个人&#xff0c; {void Hello(); }//接口虚函数&#xff0c;用来跟这个人说话 但不同的人有不用的交流方式&#xff0c;具体方式用类来实现&#xff0c;比如。 class 美国人&#…

6个高效办公的Excel小技巧,学会让你高效办公

很多人在做Excel表格的时候&#xff0c;会出现下面这种情况&#xff1a;好不容易把内容都输入好了&#xff0c;才发现文字或是数字的排列组合需要重新调整&#xff0c;这个时候头就大了&#xff0c;到底是要一个个复制黏贴&#xff0c;还是要删除后再添加&#xff1f;不管哪种方…

unity 完美像素_像素完美

unity 完美像素从Kidpix到设计系统 (From Kidpix to design systems) Did you ever create stamps in KidPix? Kidpix is bitmap drawing software that’s been around since the nineties, and I remember many happy — more like maddening — hours creating tiny pixela…

整整4个月了,尽全力组织了源码共读活动~

大家好&#xff0c;我是若川。从8月份到现在11月结束了。每周一期&#xff0c;一起读200行左右的源码&#xff0c;撰写辅助文章&#xff0c;截止到现在整整4个月了。由写有《学习源码整体架构系列》20余篇的若川【若川视野公众号号主】倾力组织&#xff0c;召集了各大厂对于源码…

kvm 学习(二)

Linux下 如何通过命令行使用现有的镜像创建、启动kvm虚拟机 这里假定已经创建好了相应的镜像&#xff1a; eg&#xff1a;我这里制作的镜像名称为zu1-centos7.img # lszu1-centos7.img 1、拷贝这个镜像到某一个目录 cp zu1-centos7.img /data2/ 2、编写镜像的配置文件&#x…

字节内部前端开发手册(完整版)开放下载!

备战2022&#xff0c;准备好了吗&#xff1f;据字节HR部门发布的最新信息&#xff0c;2019年以来字节连续3年扩招&#xff0c;而即将到来的2022年春招前端岗位数不低于3000&#xff0c;虽连年扩招&#xff0c;但是报录比却从2019年的3%下降到今年的1%。BAT等一线大厂同样有类似…

EBS中Java并发程序笔记(1)

在Oracle EBS中的Java并发程序&#xff08;Java Concurrent Program&#xff09;是系统功能中的一个亮点&#xff0c;它的出现使得用户可以在ERP系统中运行自己定义的Java程序。本文为学习笔记&#xff0c;所以不会介绍太多背景知识。 使用Java并发程序的好处&#xff1a; 当遇…

figma设计_5位来自杂乱无章的设计师的Figma技巧

figma设计When starting a design project, a fast pace and multiple design iterations can easily lead to a cluttered mess. Taking the time in the beginning to build good organizational habits will save you time later. You’ll thank your past self when you do…

hello,你知道获取元素有哪几种方式吗?

收下我的小心心&#xff01;&#xff08;害羞脸&#xff09; 根据id属性的值获取元素&#xff0c;返回来的是一个元素对象 document.getElementById("id属性的值") 根据标签名获取元素&#xff0c;返回来的是一个伪数组&#xff0c;里面保存了多个的DOM对象 documen…

设计和实现一个 Chrome 插件提升登录效率

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以点此加我微信ruochuan12 进群参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行4个月了&#xff0c;很多小伙伴表示收获颇丰。前言在我们的工作过程中&#xff0c;每当…

[待总结]redmine

先列出来&#xff0c;有空再总结转载于:https://www.cnblogs.com/gracexiao/archive/2011/11/18/2253834.html

qq空间网页设计_网页设计中的负空间

qq空间网页设计重点 (Top highlight)Because screens are limited, web design is also limited. It can be said that in the small box of the screen, each pixel is a piece of real estate.由于屏幕有限&#xff0c;因此网页设计也受到限制。 可以说&#xff0c;在屏幕的小…

前端组件化-抽象公共组件类

优化上次的组件化小demo 上次的组件化demo只是为了简单的实现前端组件化的思想&#xff0c;这次我们稍微优化一下抽离公共类 下面代码 html <div id"wrapper"></div> 复制代码js /* DOM字符串转DOM节点 */ const createStringToDom str > {const ele…

时隔一年半,我,一个卑微的前端菜鸡,又来写面经了

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以点此加我微信ruochuan12 进群参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行4个月了&#xff0c;很多小伙伴表示收获颇丰。作者&#xff1a;刮涂层_赢大奖原文地址…

javascript模版引擎-tmpl的bug修复与性能优化

http://www.planeart.cn/?p1594 http://ejohn.org/blog/javascript-micro-templating http://bbs.phpchina.com/thread-224712-1-1.html [ Noevil: 下面直接贴出改进好的MicroTemp&#xff0c;但是还是建议看一下原文&#xff0c;里面有详细的改进细节&#xff0c;和改进前后的…

2019.5.8_此书真乃宝书也_从定位参数到仅限关键字参数

《摘自流畅的Python》 此书真乃宝书也,虽说还是有点儿没懂 从定位参数到仅限关键字参数 Python最好的特性之一是提供了极为灵活的参数处理机制&#xff0c;而且Python3进一步提供了仅限关键字参数(keyword-only argument)。与之密切相关的是&#xff0c;调用函数时使用*和**“展…

用户体验与可用性测试_可用性作为用户体验的原则

用户体验与可用性测试Every UX Designer has his views and best practices. We all have a guide book created through time and experience. I want to share mine with you.每个UX设计器都有他的观点和最佳实践。 我们都有一本通过时间和经验编写的指南。 我想和你分享我的…

Jenkins插件之Deploy

deploy插件&#xff1a; Deploy Plugindeploy插件支持将War/Jar部署到远程的应用服务器上&#xff0c;例如Tomcat,JBoss,Glassfish。正在寻找或开发.NET web 应用的自动发布插件。如何回滚或重新部署先前的build&#xff1a;0&#xff09; 需要被deploy的job的结果要存档&#…