Quartz數據庫表分析

前言

上一篇文章Spring整合Quartz分佈式調度介紹了Quartz經過數據庫的方式來實現分佈式調度,經過使用數據庫來存儲trigger,job等信息,能夠在停服重啓的時候從新加載上次trigger的狀態,保證了完整性;另外一方面經過數據庫來實現鎖機制來實現分佈式調度;Quartz默認提供了11張表,本文將對這幾張表作簡要的分析。mysql

表信息

1.qrtz_blob_triggers
2.qrtz_cron_triggers
3.qrtz_simple_triggers
4.qrtz_simprop_triggers
5.qrtz_fired_triggers
6.qrtz_triggers
7.qrtz_job_details
8.qrtz_calendars
9.qrtz_paused_trigger_grps
10.qrtz_scheduler_state
11.qrtz_locks

共11張表,前6張都是關於各類triggers的信息,後面包括job,悲觀鎖,調度狀態等信息;相關表操做在類StdJDBCDelegate中,相關sql語句在StdJDBCConstants中;spring

1.qrtz_blob_triggers

自定義的triggers使用blog類型進行存儲,非自定義的triggers不會存放在此表中,Quartz提供的triggers包括:CronTrigger,CalendarIntervalTrigger,
DailyTimeIntervalTrigger以及SimpleTrigger,這幾個trigger信息會保存在後面的幾張表中;sql

2.qrtz_cron_triggers

存儲CronTrigger,這也是咱們使用最多的觸發器,在配置文件中作以下配置,便可在qrtz_cron_triggers生成記錄:數據庫

<bean id="firstCronTrigger"
    class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="firstTask" />
    <property name="cronExpression" value="0/6 * * ? * *" />
    <property name="group" value="firstCronGroup"></property>
</bean>
<bean id="firstTask"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="zh.maven.SQuartz.task.FirstTask" />
    <property name="jobDataMap">
        <map>
            <entry key="firstService" value-ref="firstService" />
        </map>
    </property>
</bean>
<bean id="firstService" class="zh.maven.SQuartz.service.FirstService"></bean>

表達式指定了每隔6秒執行一次,而後指定了要執行的task,task指定了要執行的業務,運行以後能夠查看數據表:segmentfault

mysql> select * from qrtz_cron_triggers;
+-------------+------------------+----------------+-----------------+---------------+
| SCHED_NAME  | TRIGGER_NAME     | TRIGGER_GROUP  | CRON_EXPRESSION | TIME_ZONE_ID  |
+-------------+------------------+----------------+-----------------+---------------+
| myScheduler | firstCronTrigger | firstCronGroup | 0/6 * * ? * *   | Asia/Shanghai |
+-------------+------------------+----------------+-----------------+---------------+

myScheduler是在定義SchedulerFactoryBean時指定的名稱,其餘字段均可以在上面的配置中找到;maven

3.qrtz_simple_triggers

存儲SimpleTrigger,在配置文件中作以下配置,便可在qrtz_simple_triggers生成記錄:分佈式

<bean id="firstSimpleTrigger"
    class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail" ref="firstSimpleTask" />
    <property name="startDelay" value="1000" />
    <property name="repeatInterval" value="2000" />
    <property name="repeatCount" value="5"></property>
    <property name="group" value="firstSimpleGroup"></property>
</bean>
<bean id="firstSimpleTask"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="zh.maven.SQuartz.task.SimpleFirstTask" />
    <property name="jobDataMap">
        <map>
            <entry key="firstService" value-ref="simpleFirstService" />
        </map>
    </property>
</bean>
<bean id="simpleFirstService" class="zh.maven.SQuartz.service.SimpleFirstService"></bean>

指定了開始延遲時間,重複間隔時間已經重複的次數限制,查看錶以下:測試

mysql> select * from qrtz_simple_triggers;
+-------------+--------------------+------------------+--------------+-----------------+-----------------+
| SCHED_NAME  | TRIGGER_NAME       | TRIGGER_GROUP    | REPEAT_COUNT | REPEAT_INTERVAL | TIMES_TRIGGERED |
+-------------+--------------------+------------------+--------------+-----------------+-----------------+
| myScheduler | firstSimpleTrigger | firstSimpleGroup |            5 |            2000 |               1 |
+-------------+--------------------+------------------+--------------+-----------------+-----------------+

TIMES_TRIGGERED用來記錄執行了多少次了,此值被定義在SimpleTriggerImpl中,每次執行+1,這裏定義的REPEAT_COUNT=5,實際狀況會執行6次,具體能夠查看SimpleTriggerImpl源碼:spa

public Date getFireTimeAfter(Date afterTime) {
        if (complete) {
            return null;
        }
 
        if ((timesTriggered > repeatCount)
                && (repeatCount != REPEAT_INDEFINITELY)) {
            return null;
        }
        ......
}

timesTriggered默認值爲0,當timesTriggered > repeatCount中止trigger,因此會執行6次,當執行完畢以後此記錄會被刪除;code

4.qrtz_simprop_triggers

存儲CalendarIntervalTrigger和DailyTimeIntervalTrigger兩種類型的觸發器,使用CalendarIntervalTrigger作以下配置:

<bean id="firstCalendarTrigger" class="org.quartz.impl.triggers.CalendarIntervalTriggerImpl">
    <property name="jobDataMap">
        <map>
            <entry key="jobDetail" value-ref="firstCalendarTask"></entry>
        </map>
    </property>
    <property name="key" ref="calendarTriggerKey"></property>
    <property name="repeatInterval" value="1" />
    <property name="group" value="firstCalendarGroup"></property>
</bean>
<bean id="firstCalendarTask"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="zh.maven.SQuartz.task.CalendarFirstTask" />
    <property name="jobDataMap">
        <map>
            <entry key="firstService" value-ref="calendarFirstService" />
        </map>
    </property>
</bean>
<bean id="calendarFirstService" class="zh.maven.SQuartz.service.CalendarFirstService"></bean>

CalendarIntervalTrigger沒有對應的FactoryBean,直接設置實現類CalendarIntervalTriggerImpl;指定的重複週期是1,默認單位是天,也就是天天執行一次,查看錶以下:

mysql> select * from qrtz_simprop_triggers;
+-------------+--------------------+--------------------+------------+---------------+------------+------------+------------+-------------+-------------+------------+------------+-------------+-------------+
| SCHED_NAME  | TRIGGER_NAME       | TRIGGER_GROUP      | STR_PROP_1 | STR_PROP_2    | STR_PROP_3 | INT_PROP_1 | INT_PROP_2 | LONG_PROP_1 | LONG_PROP_2 | DEC_PROP_1 | DEC_PROP_2 | BOOL_PROP_1 | BOOL_PROP_2 |
+-------------+--------------------+--------------------+------------+---------------+------------+------------+------------+-------------+-------------+------------+------------+-------------+-------------+
| myScheduler | calendarTriggerKey | firstCalendarGroup | DAY        | Asia/Shanghai | NULL       |          1 |          1 |           0 |           0 |       NULL |       NULL | 0           | 0           |
+-------------+--------------------+--------------------+------------+---------------+------------+------------+------------+-------------+-------------+------------+------------+-------------+-------------+

提供了3個string類型的參數,2個int類型的參數,2個long類型的參數,2個decimal類型的參數以及2個boolean類型的參數;具體每一個參數是什麼含義,根據不一樣的trigger類型存放各自的參數;

5.qrtz_fired_triggers

存儲已經觸發的trigger相關信息,trigger隨着時間的推移狀態發生變化,直到最後trigger執行完成,從表中被刪除;已SimpleTrigger爲例重複3次執行,查詢表:

mysql> select * from qrtz_fired_triggers;
+-------------+----------------------------------------+--------------------+------------------+---------------------------+---------------+---------------+----------+-----------+-----------------+-----------+------------------+-------------------+
| SCHED_NAME  | ENTRY_ID                               | TRIGGER_NAME       | TRIGGER_GROUP    | INSTANCE_NAME             | FIRED_TIME    | SCHED_TIME    | PRIORITY | STATE     | JOB_NAME        | JOB_GROUP | IS_NONCONCURRENT | REQUESTS_RECOVERY |
+-------------+----------------------------------------+--------------------+------------------+---------------------------+---------------+---------------+----------+-----------+-----------------+-----------+------------------+-------------------+
| myScheduler | NJD9YZGJ2-PC15241041777351524104177723 | firstSimpleTrigger | firstSimpleGroup | NJD9YZGJ2-PC1524104177735 | 1524104178499 | 1524104178472 |        0 | EXECUTING | firstSimpleTask | DEFAULT   | 0                | 0                 |
| myScheduler | NJD9YZGJ2-PC15241041777351524104177724 | firstSimpleTrigger | firstSimpleGroup | NJD9YZGJ2-PC1524104177735 | 1524104180477 | 1524104180472 |        0 | EXECUTING | firstSimpleTask | DEFAULT   | 0                | 0                 |
| myScheduler | NJD9YZGJ2-PC15241041777351524104177725 | firstSimpleTrigger | firstSimpleGroup | NJD9YZGJ2-PC1524104177735 | 1524104180563 | 1524104182472 |        0 | ACQUIRED  | NULL            | NULL      | 0                | 0                 |
+-------------+----------------------------------------+--------------------+------------------+---------------------------+---------------+---------------+----------+-----------+-----------------+-----------+------------------+-------------------+

相同的trigger和task,每觸發一次都會建立一個實例;從剛被建立的ACQUIRED狀態,到EXECUTING狀態,最後執行完從數據庫中刪除;

6.qrtz_triggers

存儲定義的trigger,以上定義的三個triggers爲例,分別是:firstSimpleTrigger,firstCalendarTrigger和firstCronTrigger,運行以後查看數據庫:

mysql> select * from qrtz_triggers;
+-------------+--------------------+--------------------+-------------------+-----------+-------------+----------------+----------------+----------+---------------+--------------+---------------+----------+---------------+---------------+----------+
| SCHED_NAME  | TRIGGER_NAME       | TRIGGER_GROUP      | JOB_NAME          | JOB_GROUP | DESCRIPTION | NEXT_FIRE_TIME | PREV_FIRE_TIME | PRIORITY | TRIGGER_STATE | TRIGGER_TYPE | START_TIME    | END_TIME | CALENDAR_NAME | MISFIRE_INSTR | JOB_DATA |
+-------------+--------------------+--------------------+-------------------+-----------+-------------+----------------+----------------+----------+---------------+--------------+---------------+----------+---------------+---------------+----------+
| myScheduler | calendarTriggerKey | firstCalendarGroup | firstCalendarTask | DEFAULT   | NULL        |  1524203884719 |  1524117484719 |        5 | WAITING       | CAL_INT      | 1524117484719 |        0 | NULL          |             0 |          |
| myScheduler | firstCronTrigger   | firstCronGroup     | firstTask         | DEFAULT   | NULL        |  1524117492000 |  1524117486000 |        0 | ACQUIRED      | CRON         | 1524117483000 |        0 | firstCalendar |             0 |          |
| myScheduler | firstSimpleTrigger | firstSimpleGroup   | firstSimpleTask   | DEFAULT   | NULL        |             -1 |  1524117488436 |        0 | COMPLETE      | SIMPLE       | 1524117484436 |        0 | NULL          |             0 |          |
+-------------+--------------------+--------------------+-------------------+-----------+-------------+----------------+----------------+----------+---------------+--------------+---------------+----------+---------------+---------------+----------+

和qrtz_fired_triggers存放的不同,無論trigger觸發了多少次都只有一條記錄,TRIGGER_STATE用來標識當前trigger的狀態;firstCalendarTask天天執行一次,執行完以後一直是WAITING狀態;firstCronTrigger每6秒執行一次狀態是ACQUIRED狀態;firstSimpleTrigger重複執行6次後狀態爲COMPLETE,而且會被刪除;

7.qrtz_job_details

存儲jobDetails信息,相關信息在定義的時候指定,如上面定義的JobDetailFactoryBean,查詢數據庫:

mysql> select * from qrtz_job_details;
+-------------+-------------------+-----------+-------------+-----------------------------------------+------------+------------------+----------------+-------------------+----------+
| SCHED_NAME  | JOB_NAME          | JOB_GROUP | DESCRIPTION | JOB_CLASS_NAME                          | IS_DURABLE | IS_NONCONCURRENT | IS_UPDATE_DATA | REQUESTS_RECOVERY | JOB_DATA |
+-------------+-------------------+-----------+-------------+-----------------------------------------+------------+------------------+----------------+-------------------+----------+
| myScheduler | firstCalendarTask | DEFAULT   | NULL        | zh.maven.SQuartz.task.CalendarFirstTask | 0          | 0                | 0              | 0                 | |
| myScheduler | firstSimpleTask   | DEFAULT   | NULL        | zh.maven.SQuartz.task.SimpleFirstTask   | 0          | 0                | 0              | 0                 | |
| myScheduler | firstTask         | DEFAULT   | NULL        | zh.maven.SQuartz.task.FirstTask         | 0          | 0                | 0              | 0                 | |
+-------------+-------------------+-----------+-------------+-----------------------------------------+------------+------------------+----------------+-------------------+----------+

JOB_DATA存放的就是定義task時指定的jobDataMap屬性,因此此屬性須要實現Serializable接口,方便持久化到數據庫;

8.qrtz_calendars

Quartz爲咱們提供了日曆的功能,能夠本身定義一個時間段,能夠控制觸發器在這個時間段內觸發或者不觸發;如今提供6種類型:AnnualCalendar,CronCalendar,DailyCalendar,HolidayCalendar,MonthlyCalendar,WeeklyCalendar;如下使用CronCalendar爲例:

<bean id="firstCalendar" class="org.quartz.impl.calendar.CronCalendar">
    <constructor-arg value="0/5 * * ? * *"></constructor-arg>
</bean>
<bean id="firstCronTrigger"
    class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="firstTask" />
    <property name="cronExpression" value="0/6 * * ? * *" />
    <property name="group" value="firstCronGroup"></property>
    <property name="calendarName" value="firstCalendar"></property>
</bean>
<bean id="scheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="schedulerName" value="myScheduler"></property>
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:quartz.properties" />
    <property name="triggers">
        <list>
            <ref bean="firstCronTrigger" />
        </list>
    </property>
    <property name="calendars">
        <map>
            <entry key="firstCalendar" value-ref="firstCalendar"></entry>
        </map>
    </property>
</bean>

定義了一個排除每隔5秒的CronCalendar,而後在firstCronTrigger中指定了calendarName,而且須要在SchedulerFactoryBean中定義calendars;由於firstCronTrigger每6秒執行一次,而CronCalendar排除每隔5秒,因此會出現firstCronTrigger在第5次觸發的時候須要等待12秒,結果以下:

20180419 15:09:06---start FirstService
20180419 15:09:08---end FirstService
20180419 15:09:12---start FirstService
20180419 15:09:14---end FirstService
20180419 15:09:18---start FirstService
20180419 15:09:20---end FirstService
20180419 15:09:24---start FirstService
20180419 15:09:26---end FirstService
20180419 15:09:36---start FirstService
20180419 15:09:38---end FirstService

查詢保存在數據中的CronCalendar:

mysql> select * from qrtz_calendars;
+-------------+---------------+----------+
| SCHED_NAME  | CALENDAR_NAME | CALENDAR |
+-------------+---------------+----------+
| myScheduler | firstCalendar | |
+-------------+---------------+----------+

CALENDAR存放的是CronCalendar序列化以後的數據;

9.qrtz_paused_trigger_grps

存放暫停掉的觸發器,測試手動暫停firstCronTrigger,代碼以下:

public class App {
    public static void main(String[] args) {
        final AbstractApplicationContext context = new ClassPathXmlApplicationContext("quartz.xml");
        final StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
        try {
            Thread.sleep(4000);
            scheduler.pauseTriggers(GroupMatcher.triggerGroupEquals("firstCronGroup"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

啓動以後延遲4秒後暫停firstCronTrigger,這裏傳遞的參數group,而後查看數據庫:

mysql> select * from qrtz_paused_trigger_grps;
+-------------+----------------+
| SCHED_NAME  | TRIGGER_GROUP  |
+-------------+----------------+
| myScheduler | firstCronGroup |
+-------------+----------------+

由於已經入庫,因此重啓以後firstCronGroup仍是處於暫停狀態,firstCronTrigger不會運行;

10.qrtz_scheduler_state

存儲全部節點的scheduler,會按期檢查scheduler是否失效,啓動多個scheduler,查詢數據庫:

mysql> select * from qrtz_scheduler_state;
+-------------+---------------------------+-------------------+------------------+
| SCHED_NAME  | INSTANCE_NAME             | LAST_CHECKIN_TIME | CHECKIN_INTERVAL |
+-------------+---------------------------+-------------------+------------------+
| myScheduler | NJD9YZGJ2-PC1524209095408 |     1524209113973 |             1000 |
| myScheduler | NJD9YZGJ2-PC1524209097649 |     1524209113918 |             1000 |
+-------------+---------------------------+-------------------+------------------+

記錄了最後最新的檢查時間,在quartz.properties中設置了CHECKIN_INTERVAL爲1000,也就是每秒檢查一次;

11.qrtz_locks

Quartz提供的鎖表,爲多個節點調度提供分佈式鎖,實現分佈式調度,默認有2個鎖:

mysql> select * from qrtz_locks;
+-------------+----------------+
| SCHED_NAME  | LOCK_NAME      |
+-------------+----------------+
| myScheduler | STATE_ACCESS   |
| myScheduler | TRIGGER_ACCESS |
+-------------+----------------+

STATE_ACCESS主要用在scheduler按期檢查是否失效的時候,保證只有一個節點去處理已經失效的scheduler;
TRIGGER_ACCESS主要用在TRIGGER被調度的時候,保證只有一個節點去執行調度;

總結

本文對這11張表作了簡要的分析,介紹了每張表具體是用來存儲什麼的,而且給了簡單的實例;其實若是要實現一個trigger的管理系統,其實也就是對這幾張表的維護。

相關文章
相關標籤/搜索