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.pswp.cn/news/275174.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275174.shtml
英文地址,請注明出處:http://en.pswp.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的結果要存檔&#…