Download WordPress Themes, Happy Birthday Wishes

Java Quartz with MySQL Example

1. Introduction

In this article, we will go through the configuration needed to setup MySQL, the most famous open source database, with Quartz, a very popular open source job scheduling library that can be used in Java applications. The main concept of Quartz is that a scheduler holds a list of jobs that are triggered at specific times or repeatedly. In the code examples we will see how to persist this data in MySQL.

2. Project Setup

To run the code examples of this post, we will use the following technologies:

  • Java 8
  • MySQL Server 5.7.26
  • Quartz 2.2.1
  • MySQL JDBC 5.1.34
  • SLF4J 1.7.26
  • Logback 1.2.3
  • Maven 3.3.3
  • Eclipse 4.10.0

2.1 Install MySQL Server

To run the code examples we will have to install the MySQL Community Server. From this link, download the MySQL Community Server 5.7.26 for your operating system and follow the installation instructions. Once MySQL is installed, you should be prompted to change the root password. Do not forget that password as it will be the only way to login to MySQL. Finally, MySQL should automatically start as a service.

2.2 Create a new Maven Project

In Eclipse, create a new Maven Project and add the following dependencies to the pom.xml:

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javacodegeeks</groupId>
    <artifactId>java-quartz-mysql</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <description>Java Quartz with MySQL Example</description>
    
    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
        <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
</project>

3. Create the Quartz database

The first step, before running the code examples, is to create the database and tables required by Quartz to persist data. From the the MySQL Command-Line Client execute the following commands:

pom.xml

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
CREATE DATABASE IF NOT EXISTS QUARTZ_SCHEMA;
USE QUARTZ_SCHEMA;
CREATE TABLE IF NOT EXISTS QRTZ_JOB_DETAILS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  JOB_NAME  VARCHAR(200) NOT NULL,
  JOB_GROUP VARCHAR(200) NOT NULL,
  DESCRIPTION VARCHAR(250) NULL,
  JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
  IS_DURABLE VARCHAR(1) NOT NULL,
  IS_NONCONCURRENT VARCHAR(1) NOT NULL,
  IS_UPDATE_DATA VARCHAR(1) NOT NULL,
  REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
  JOB_DATA BLOB NULL,
  PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  JOB_NAME  VARCHAR(200) NOT NULL,
  JOB_GROUP VARCHAR(200) NOT NULL,
  DESCRIPTION VARCHAR(250) NULL,
  NEXT_FIRE_TIME BIGINT(13) NULL,
  PREV_FIRE_TIME BIGINT(13) NULL,
  PRIORITY INTEGER NULL,
  TRIGGER_STATE VARCHAR(16) NOT NULL,
  TRIGGER_TYPE VARCHAR(8) NOT NULL,
  START_TIME BIGINT(13) NOT NULL,
  END_TIME BIGINT(13) NULL,
  CALENDAR_NAME VARCHAR(200) NULL,
  MISFIRE_INSTR SMALLINT(2) NULL,
  JOB_DATA BLOB NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
  REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_SIMPLE_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  REPEAT_COUNT BIGINT(7) NOT NULL,
  REPEAT_INTERVAL BIGINT(12) NOT NULL,
  TIMES_TRIGGERED BIGINT(10) NOT NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_CRON_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  CRON_EXPRESSION VARCHAR(200) NOT NULL,
  TIME_ZONE_ID VARCHAR(80),
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_SIMPROP_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  STR_PROP_1 VARCHAR(512) NULL,
  STR_PROP_2 VARCHAR(512) NULL,
  STR_PROP_3 VARCHAR(512) NULL,
  INT_PROP_1 INT NULL,
  INT_PROP_2 INT NULL,
  LONG_PROP_1 BIGINT NULL,
  LONG_PROP_2 BIGINT NULL,
  DEC_PROP_1 NUMERIC(13,4) NULL,
  DEC_PROP_2 NUMERIC(13,4) NULL,
  BOOL_PROP_1 VARCHAR(1) NULL,
  BOOL_PROP_2 VARCHAR(1) NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_BLOB_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  BLOB_DATA BLOB NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_CALENDARS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  CALENDAR_NAME  VARCHAR(200) NOT NULL,
  CALENDAR BLOB NOT NULL,
  PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE IF NOT EXISTS QRTZ_PAUSED_TRIGGER_GRPS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_GROUP  VARCHAR(200) NOT NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE IF NOT EXISTS QRTZ_FIRED_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  ENTRY_ID VARCHAR(95) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  INSTANCE_NAME VARCHAR(200) NOT NULL,
  FIRED_TIME BIGINT(13) NOT NULL,
  SCHED_TIME BIGINT(13) NOT NULL,
  PRIORITY INTEGER NOT NULL,
  STATE VARCHAR(16) NOT NULL,
  JOB_NAME VARCHAR(200) NULL,
  JOB_GROUP VARCHAR(200) NULL,
  IS_NONCONCURRENT VARCHAR(1) NULL,
  REQUESTS_RECOVERY VARCHAR(1) NULL,
  PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE IF NOT EXISTS QRTZ_SCHEDULER_STATE
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  INSTANCE_NAME VARCHAR(200) NOT NULL,
  LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
  CHECKIN_INTERVAL BIGINT(13) NOT NULL,
  PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE IF NOT EXISTS QRTZ_LOCKS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  LOCK_NAME  VARCHAR(40) NOT NULL,
  PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

As we see from the above commands, we create a database named QUARTZ_SCHEMA and several tables in it. These tables will persist the jobs, schedulers and triggers etc required by Quartz. You don’t need to memorize these commands, as they are provided by Quartz.

4. Setup the Quartz properties

In our maven project we add a quartz.properties file under src/main/resources, , which will hold the properties required by Quartz to connect to MySQL:

quartz.properties

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
# Database properties
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.dataSource.quartzDataSource.driver=com.mysql.jdbc.Driver
org.quartz.dataSource.quartzDataSource.URL=jdbc:mysql://localhost:3306/quartz_schema
org.quartz.dataSource.quartzDataSource.user=root
org.quartz.dataSource.quartzDataSource.password=change_me
# Non-database specific properties
org.quartz.scheduler.instanceName=DatabaseScheduler
org.quartz.scheduler.instanceId=EXAMPLE_INSTANCE
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.threadPool.threadCount=1

In the above properties, you should change the org.quartz.dataSource.quartzDataSource.password to the one you configured when you installed MySQL. Let’s see in more details the database properties one by one:

  • org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX – Handles database commits and rollbacks
  • org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate– Abstract class for JDBC drivers to connect to database
  • org.quartz.jobStore.dataSource=quartzDataSource – Random name of datasource
  • org.quartz.jobStore.tablePrefix=QRTZ_ – The prefix of the Quartz tables created
  • org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool – Simple implementation of a thread pool with fixed number of Threads
  • org.quartz.dataSource.quartzDataSource.driver=com.mysql.jdbc.Driver – The MySQL JDBC driver
  • org.quartz.dataSource.quartzDataSource.URL=jdbc:mysql://localhost:3306/quartz_schema– The MySQL IP, port and database name the Quartz tables were created in
  • org.quartz.dataSource.quartzDataSource.user=root– The MySQL user
  • org.quartz.dataSource.quartzDataSource.password=change_me – The MySQL password

5. Run the example

We have finished the configuration of the database and properties to connect to MySQL. In this step, we will implement the code required to run a job and persist the data into MySQL:

SimpleJob.java

1
2
3
4
5
6
7
8
public class SimpleJob implements Job {
    
    private final Logger log = LoggerFactory.getLogger(SimpleJob.class);
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleJob executed!");
    }
}

QuartzExample.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class QuartzExample {
    public void run() throws Exception {
        // create the scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // define the job and tie it to the SimpleJob class
        JobDetail job = JobBuilder.newJob(SimpleJob.class)
                .withIdentity("myJob", "myGroup")
                .build();
        // create the trigger and define its schedule to run every 3 seconds
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger", "myGroup")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();
        // add the job details to the scheduler and associate it with the trigger
        scheduler.scheduleJob(job, trigger);
        // start the scheduler
        scheduler.start();
        // wait long enough to see the job execution
        Thread.sleep(5 * 1000);
        // shutdown the scheduler
        scheduler.shutdown(true);
    }
    public static void main(String[] args) throws Exception {
        // run the example
        QuartzExample example = new QuartzExample();
        example.run();
    }
}

In the example above, we create the SimpleJob job, a very simple job which only outputs a single line of code when it gets executed. In the QuartzExample class, this job is added to the scheduler and set for execution every 3 seconds. Finally the scheduler shuts down after 8 seconds (see Thread.sleep(8 * 1000)). Let’s run main method of QuartzExample class and see the output:

Output

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
May 15, 2019 7:49:34 AM com.mchange.v2.log.MLog
INFO: MLog clients using java 1.4+ standard logging.
May 15, 2019 7:49:34 AM com.mchange.v2.c3p0.C3P0Registry banner
INFO: Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10]
07:49:34.461 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
07:49:34.526 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
07:49:34.526 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.2.1 created.
07:49:34.527 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Using thread monitor-based data access locking (synchronization).
07:49:34.528 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - JobStoreTX initialized.
07:49:34.529 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.1) 'DatabaseScheduler' with instanceId 'EXAMPLE_INSTANCE'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 1 threads.
  Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered.
07:49:34.529 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DatabaseScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
07:49:34.529 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.2.1
07:49:34.535 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: main
07:49:34.536 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: main
07:49:34.536 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: main
May 15, 2019 7:49:34 AM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> z8kflta21fk59q91urzcyj|5ccd43c2, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> z8kflta21fk59q91urzcyj|5ccd43c2, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/QUARTZ_SCHEMA, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
07:49:34.990 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Adding TriggerPersistenceDelegate of type: org.quartz.impl.jdbcjobstore.SimpleTriggerPersistenceDelegate
07:49:34.991 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Adding TriggerPersistenceDelegate of type: org.quartz.impl.jdbcjobstore.CronTriggerPersistenceDelegate
07:49:34.996 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Adding TriggerPersistenceDelegate of type: org.quartz.impl.jdbcjobstore.CalendarIntervalTriggerPersistenceDelegate
07:49:35.000 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Adding TriggerPersistenceDelegate of type: org.quartz.impl.jdbcjobstore.DailyTimeIntervalTriggerPersistenceDelegate
07:49:35.081 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: main
07:49:35.083 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: main
07:49:35.083 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: main
07:49:35.083 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: main
07:49:35.095 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Freed 0 triggers from 'acquired' / 'blocked' state.
07:49:35.101 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Found 0 triggers that missed their scheduled fire-time.
07:49:35.106 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovering 0 jobs that were in-progress at the time of the last shut-down.
07:49:35.106 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovery complete.
07:49:35.107 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 'complete' triggers.
07:49:35.109 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job entries.
07:49:35.110 [main] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: main
07:49:35.111 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - JobStore background threads started (as scheduler was started).
07:49:35.111 [QuartzScheduler_DatabaseScheduler-EXAMPLE_INSTANCE_MisfireHandler] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - MisfireHandler: scanning for misfires...
07:49:35.111 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DatabaseScheduler_$_EXAMPLE_INSTANCE started.
07:49:35.114 [QuartzScheduler_DatabaseScheduler-EXAMPLE_INSTANCE_MisfireHandler] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - Found 0 triggers that missed their scheduled fire-time.
07:49:35.146 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
07:49:35.148 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: DatabaseScheduler_QuartzSchedulerThread
07:49:35.148 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: DatabaseScheduler_QuartzSchedulerThread
07:49:35.148 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: DatabaseScheduler_QuartzSchedulerThread
07:49:35.172 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: DatabaseScheduler_QuartzSchedulerThread
07:49:35.177 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.javacodegeeks.quartz.builders.SimpleJob
07:49:35.179 [DatabaseScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
07:49:35.180 [DatabaseScheduler_Worker-1] INFO com.javacodegeeks.quartz.builders.SimpleJob - SimpleJob executed!
07:49:35.181 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: DatabaseScheduler_Worker-1
07:49:35.181 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: DatabaseScheduler_Worker-1
07:49:35.181 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: DatabaseScheduler_Worker-1
07:49:35.196 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: DatabaseScheduler_Worker-1
07:49:35.217 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
07:49:37.534 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: DatabaseScheduler_QuartzSchedulerThread
07:49:37.534 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: DatabaseScheduler_QuartzSchedulerThread
07:49:37.535 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: DatabaseScheduler_QuartzSchedulerThread
07:49:37.555 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: DatabaseScheduler_QuartzSchedulerThread
07:49:37.556 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.javacodegeeks.quartz.builders.SimpleJob
07:49:37.556 [DatabaseScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
07:49:37.556 [DatabaseScheduler_Worker-1] INFO com.javacodegeeks.quartz.builders.SimpleJob - SimpleJob executed!
07:49:37.556 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: DatabaseScheduler_Worker-1
07:49:37.556 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: DatabaseScheduler_Worker-1
07:49:37.556 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: DatabaseScheduler_Worker-1
07:49:37.561 [DatabaseScheduler_Worker-1] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: DatabaseScheduler_Worker-1
07:49:37.581 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
07:49:40.115 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DatabaseScheduler_$_EXAMPLE_INSTANCE shutting down.
07:49:40.116 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DatabaseScheduler_$_EXAMPLE_INSTANCE paused.
07:49:40.116 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is desired by: DatabaseScheduler_QuartzSchedulerThread
07:49:40.116 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' is being obtained: DatabaseScheduler_QuartzSchedulerThread
07:49:40.116 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' given to: DatabaseScheduler_QuartzSchedulerThread
07:49:40.132 [DatabaseScheduler_QuartzSchedulerThread] DEBUG org.quartz.impl.jdbcjobstore.SimpleSemaphore - Lock 'TRIGGER_ACCESS' retuned by: DatabaseScheduler_QuartzSchedulerThread
07:49:40.133 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutting down threadpool...
07:49:40.578 [DatabaseScheduler_Worker-1] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.
07:49:40.579 [main] DEBUG org.quartz.simpl.SimpleThreadPool - No executing jobs remaining, all threads stopped.
07:49:40.579 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutdown of threadpool complete.
07:49:40.581 [main] DEBUG org.quartz.impl.jdbcjobstore.JobStoreTX - JobStore background threads shutdown.
07:49:40.581 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DatabaseScheduler_$_EXAMPLE_INSTANCE shutdown complete.

From the above output, we see that the job ran 2 times in total, at an interval of 3 seconds, before the scheduler was manually shut down by the main thread. We see in line 24 that Quartz manages to connect to the MySQL database we configured. In the next section, we will examine what data is saved into the database tables we created.

6. Examine the database

In the previous section, we scheduled a very simple job using a trigger that runs at an interval of 3 seconds. Let’s see what data is saved in MySQL when the job gets executed:

Queries

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT * FROM quartz_schema.qrtz_job_details;
+-------------------+----------+-----------+-------------+-----------------------------+------------+------------------+----------------+-------------------+----------------+
| SCHED_NAME        | JOB_NAME | JOB_GROUP | DESCRIPTION | JOB_CLASS_NAME              | IS_DURABLE | IS_NONCONCURRENT | IS_UPDATE_DATA | REQUESTS_RECOVERY | JOB_DATA       |
+-------------------+----------+-----------+-------------+-----------------------------+------------+------------------+----------------+-------------------+----------------+
| DatabaseScheduler | myJob    | myGroup   | NULL        | com.javacodegeeks.SimpleJob | 0          | 0                | 0              | 0                 | (Binary/Image) |
+-------------------+----------+-----------+-------------+-----------------------------+------------+------------------+----------------+-------------------+----------------+
1 row in set (0.00 sec)
SELECT * FROM quartz_schema.qrtz_simple_triggers;
+-------------------+--------------+---------------+--------------+-----------------+-----------------+
| SCHED_NAME        | TRIGGER_NAME | TRIGGER_GROUP | REPEAT_COUNT | REPEAT_INTERVAL | TIMES_TRIGGERED |
+-------------------+--------------+---------------+--------------+-----------------+-----------------+
| DatabaseScheduler | myTrigger    | myGroup       |           -1 |            3000 |               2 |
+-------------------+--------------+---------------+--------------+-----------------+-----------------+
1 row in set (0.00 sec)
SELECT * FROM quartz_schema.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 |
+-------------------+--------------+---------------+----------+-----------+-------------+----------------+----------------+----------+---------------+--------------+---------------+----------+---------------+---------------+----------+
| DatabaseScheduler | myTrigger    | myGroup       | myJob    | myGroup   | NULL        |  1557895780532 |  1557895777532 |        5 | WAITING       | SIMPLE       | 1557895774532 |        0 | NULL          |             0 |          |
+-------------------+--------------+---------------+----------+-----------+-------------+----------------+----------------+----------+---------------+--------------+---------------+----------+---------------+---------------+----------+
1 row in set (0.00 sec)

As we see from the output of the 3 queries we executed above, the job data (namegroupJava class) is saved in the quartz_schema.qrtz_job_details table and the trigger data (namegroupinterval) is saved in the quartz_schema.qrtz_simple_triggers table. The most important data, which is the job execution data, is saved in the quartz_schema.qrtz_triggers table. In this table, some job and trigger data is also saved, but we also find the last and next execution time of the job. This data is very important for Quartz to schedule the job.

7. Conclusion

In this article, we setup a new MySQL database and tables in which we saved the jobs and triggers of Quartz. We went through a code example using a simple project which schedules a job and saves the Quartz data into MySQL. Finally, we examined the data saved by Quartz into the database.

8. Download the Eclipse project

Download
You can download the full source code of the above example here: Java Quartz with MySQL Example

Leave a Reply

Your email address will not be published. Required fields are marked *

*