Quartz Enterprise Job Scheduler - A richly featured, open source job scheduling library that can be integrated within virtually any Java application
—
Comprehensive data persistence system in Quartz supporting both in-memory and database storage with sophisticated connection pooling, transaction management, and database-specific optimizations. This system provides the foundation for job and trigger persistence, clustering, and enterprise-scale deployments.
Base interface for all job and trigger persistence implementations.
/**
* Interface for storing and retrieving jobs and triggers
*/
interface JobStore {
/**
* Initialize the job store
* @param loadHelper class loading helper
* @param signaler scheduler signaler for notifications
* @throws SchedulerConfigException if initialization fails
*/
void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException;
/**
* Start the job store for use
* @throws SchedulerException if startup fails
*/
void schedulerStarted() throws SchedulerException;
/**
* Shutdown the job store
*/
void shutdown();
/**
* Store a job and its associated triggers
* @param newJob the job to store
* @param newTriggers triggers associated with the job
* @param replace whether to replace existing job
* @throws SchedulerException if storage fails
*/
void storeJobAndTrigger(JobDetail newJob, OperableTrigger newTrigger) throws SchedulerException;
/**
* Store a job
* @param newJob the job to store
* @param replaceExisting whether to replace existing job
* @throws SchedulerException if storage fails
*/
void storeJob(JobDetail newJob, boolean replaceExisting) throws SchedulerException;
/**
* Store a trigger
* @param newTrigger the trigger to store
* @param replaceExisting whether to replace existing trigger
* @throws SchedulerException if storage fails
*/
void storeTrigger(OperableTrigger newTrigger, boolean replaceExisting) throws SchedulerException;
/**
* Remove a job and all its triggers
* @param jobKey the job key
* @return true if job was removed
* @throws SchedulerException if removal fails
*/
boolean removeJob(JobKey jobKey) throws SchedulerException;
/**
* Remove a trigger
* @param triggerKey the trigger key
* @return true if trigger was removed
* @throws SchedulerException if removal fails
*/
boolean removeTrigger(TriggerKey triggerKey) throws SchedulerException;
/**
* Retrieve a job
* @param jobKey the job key
* @return the job detail or null if not found
* @throws SchedulerException if retrieval fails
*/
JobDetail retrieveJob(JobKey jobKey) throws SchedulerException;
/**
* Retrieve a trigger
* @param triggerKey the trigger key
* @return the trigger or null if not found
* @throws SchedulerException if retrieval fails
*/
OperableTrigger retrieveTrigger(TriggerKey triggerKey) throws SchedulerException;
/**
* Acquire triggers ready to fire
* @param noLaterThan maximum fire time
* @param maxCount maximum number of triggers
* @param timeWindow time window for acquisition
* @return list of trigger fire bundles
* @throws SchedulerException if acquisition fails
*/
List<OperableTrigger> acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) throws SchedulerException;
/**
* Inform job store that triggers have been fired
* @param triggers the fired triggers
* @return firing results
* @throws SchedulerException if operation fails
*/
List<TriggerFiredResult> triggersFired(List<OperableTrigger> triggers) throws SchedulerException;
/**
* Check if job store supports persistence
* @return true if persistent
*/
boolean supportsPersistence();
/**
* Check if job store is clustered
* @return true if clustered
*/
boolean isClustered();
}In-memory job store implementation for single-node, volatile storage.
/**
* In-memory job store - data is lost when JVM stops
*/
class RAMJobStore implements JobStore {
/**
* Create in-memory job store
*/
RAMJobStore();
/**
* Set misfire threshold in milliseconds
* @param misfireThreshold threshold in milliseconds
*/
void setMisfireThreshold(long misfireThreshold);
/**
* Get misfire threshold
* @return misfire threshold in milliseconds
*/
long getMisfireThreshold();
// Inherits all JobStore methods
// Data stored in memory - not persistent across restarts
// Fast performance, no database dependencies
// Single scheduler instance only
}Database-backed job stores for persistent, clustered storage.
/**
* JDBC job store with transaction management
*/
class JobStoreTX extends JobStoreSupport {
/**
* Create JDBC job store with transaction management
*/
JobStoreTX();
// Manages its own database transactions
// Suitable for standalone applications
// Uses JobStoreSupport base functionality
}
/**
* JDBC job store for container-managed transactions
*/
class JobStoreCMT extends JobStoreSupport {
/**
* Create JDBC job store for container-managed transactions
*/
JobStoreCMT();
/**
* Set whether to use non-managed transactions for locks
* @param nonManagedTXForLocks true to use non-managed transactions
*/
void setNonManagedTXForLocks(boolean nonManagedTXForLocks);
// Works with container-managed transactions (CMT)
// Suitable for J2EE application servers
// Transaction boundaries managed by container
}
/**
* Base class for JDBC job store implementations
*/
abstract class JobStoreSupport implements JobStore {
/**
* Set the database table prefix
* @param tablePrefix prefix for all Quartz tables
*/
void setTablePrefix(String tablePrefix);
/**
* Set the data source name
* @param dataSource JNDI name or direct data source name
*/
void setDataSource(String dataSource);
/**
* Set the driver delegate class for database-specific SQL
* @param driverDelegateClass fully qualified class name
*/
void setDriverDelegateClass(String driverDelegateClass);
/**
* Set whether job store is clustered
* @param isClustered true for clustered operation
*/
void setIsClustered(boolean isClustered);
/**
* Set cluster check-in interval
* @param clusterCheckinInterval interval in milliseconds
*/
void setClusterCheckinInterval(long clusterCheckinInterval);
/**
* Set maximum misfire threshold
* @param misfireThreshold threshold in milliseconds
*/
void setMisfireThreshold(long misfireThreshold);
/**
* Set whether to use database locks
* @param useDBLocks true to use database locks
*/
void setUseDBLocks(boolean useDBLocks);
/**
* Set lock handler for database locking
* @param lockHandler lock handler implementation
*/
void setLockHandler(Semaphore lockHandler);
/**
* Set whether to acquire triggers within lock
* @param acquireTriggersWithinLock true to use lock
*/
void setAcquireTriggersWithinLock(boolean acquireTriggersWithinLock);
}Database-specific SQL implementations for optimal performance.
/**
* Base delegate providing standard SQL operations
*/
class StdJDBCDelegate implements DriverDelegate {
/**
* Get the database-specific SQL for operations
*/
String getSelectNextTriggerToAcquireSQL();
String getInsertJobDetailSQL();
String getUpdateJobDetailSQL();
String getSelectJobDetailSQL();
String getDeleteJobDetailSQL();
// Additional SQL operation methods
}
/**
* PostgreSQL-specific optimizations
*/
class PostgreSQLDelegate extends StdJDBCDelegate {
// PostgreSQL-specific SQL optimizations
// Better handling of BYTEA columns
// PostgreSQL-specific lock handling
}
/**
* Oracle-specific optimizations
*/
class OracleDelegate extends StdJDBCDelegate {
// Oracle-specific SQL optimizations
// BLOB/CLOB handling improvements
// Oracle-specific rowid operations
}
/**
* MySQL-specific optimizations
*/
class MySQLDelegate extends StdJDBCDelegate {
// MySQL-specific SQL optimizations
// MySQL-specific data type handling
}
/**
* SQL Server-specific optimizations
*/
class MSSQLDelegate extends StdJDBCDelegate {
// SQL Server-specific SQL optimizations
// SQL Server-specific lock handling
}
/**
* DB2-specific optimizations
*/
class DB2v6Delegate extends StdJDBCDelegate {
// DB2-specific SQL optimizations
}
/**
* DB2 version 7+ optimizations
*/
class DB2v7Delegate extends DB2v6Delegate {
// Enhanced DB2 features for version 7+
}
/**
* CloudscapeDelegate for Apache Derby
*/
class CloudscapeDelegate extends StdJDBCDelegate {
// Apache Derby / Cloudscape optimizations
}
/**
* H2 database optimizations
*/
class H2Delegate extends StdJDBCDelegate {
// H2-specific optimizations
}
/**
* HSQLDB optimizations
*/
class HSQLDBDelegate extends StdJDBCDelegate {
// HSQLDB-specific optimizations
}Sophisticated connection pool management for database operations.
/**
* Interface for providing database connections
*/
interface ConnectionProvider {
/**
* Get a database connection
* @return database connection
* @throws SQLException if connection cannot be obtained
*/
Connection getConnection() throws SQLException;
/**
* Shutdown the connection provider
* @throws SQLException if shutdown fails
*/
void shutdown() throws SQLException;
/**
* Initialize the connection provider
* @throws SQLException if initialization fails
*/
void initialize() throws SQLException;
}
/**
* Interface for pooling connection providers
*/
interface PoolingConnectionProvider extends ConnectionProvider {
/**
* Get the current number of connections in the pool
* @return connection count
*/
int getPoolSize();
/**
* Get the maximum pool size
* @return maximum connections
*/
int getMaxPoolSize();
/**
* Get the current number of connections in use
* @return connections in use
*/
int getConnectionsInUse();
}
/**
* C3P0 connection pooling implementation
*/
class C3p0PoolingConnectionProvider implements PoolingConnectionProvider {
/**
* Set maximum pool size
* @param maxPoolSize maximum number of connections
*/
void setMaxPoolSize(int maxPoolSize);
/**
* Set minimum pool size
* @param minPoolSize minimum number of connections
*/
void setMinPoolSize(int minPoolSize);
/**
* Set initial pool size
* @param initialPoolSize initial number of connections
*/
void setInitialPoolSize(int initialPoolSize);
/**
* Set maximum idle time for connections
* @param maxIdleTime idle time in seconds
*/
void setMaxIdleTime(int maxIdleTime);
/**
* Set connection test query
* @param idleConnectionTestPeriod test period in seconds
*/
void setIdleConnectionTestPeriod(int idleConnectionTestPeriod);
/**
* Set connection validation query
* @param validationQuery SQL query for validation
*/
void setValidationQuery(String validationQuery);
}
/**
* HikariCP connection pooling implementation
*/
class HikariCpPoolingConnectionProvider implements PoolingConnectionProvider {
/**
* Set maximum pool size
* @param maximumPoolSize maximum number of connections
*/
void setMaximumPoolSize(int maximumPoolSize);
/**
* Set minimum idle connections
* @param minimumIdle minimum idle connections
*/
void setMinimumIdle(int minimumIdle);
/**
* Set maximum connection lifetime
* @param maxLifetime lifetime in milliseconds
*/
void setMaxLifetime(long maxLifetime);
/**
* Set connection timeout
* @param connectionTimeout timeout in milliseconds
*/
void setConnectionTimeout(long connectionTimeout);
/**
* Set idle timeout
* @param idleTimeout timeout in milliseconds
*/
void setIdleTimeout(long idleTimeout);
/**
* Set connection test query
* @param connectionTestQuery SQL query for testing
*/
void setConnectionTestQuery(String connectionTestQuery);
}
/**
* JNDI-based connection provider
*/
class JNDIConnectionProvider implements ConnectionProvider {
/**
* Set JNDI name for data source lookup
* @param jndiURL JNDI URL for data source
*/
void setJndiURL(String jndiURL);
/**
* Set initial context factory
* @param java_naming_factory_initial factory class name
*/
void setJava_naming_factory_initial(String java_naming_factory_initial);
/**
* Set naming provider URL
* @param java_naming_provider_url provider URL
*/
void setJava_naming_provider_url(String java_naming_provider_url);
}
/**
* Connection manager for managing multiple data sources
*/
class DBConnectionManager {
/**
* Get singleton instance
* @return connection manager instance
*/
static DBConnectionManager getInstance();
/**
* Add connection provider
* @param dataSourceName name of data source
* @param provider connection provider implementation
*/
void addConnectionProvider(String dataSourceName, ConnectionProvider provider);
/**
* Get connection from named data source
* @param dataSourceName name of data source
* @return database connection
* @throws SQLException if connection cannot be obtained
*/
Connection getConnection(String dataSourceName) throws SQLException;
/**
* Shutdown all connection providers
*/
void shutdown();
}Usage Examples:
// Basic JDBC JobStore Configuration (quartz.properties)
/*
# Use JDBC job store with transaction management
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# Database-specific delegate
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
# Data source configuration
org.quartz.jobStore.dataSource = myDS
# Table prefix (default is QRTZ_)
org.quartz.jobStore.tablePrefix = QRTZ_
# Clustering settings
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# Misfire handling
org.quartz.jobStore.misfireThreshold = 60000
# Data source definition
org.quartz.dataSource.myDS.driver = org.postgresql.Driver
org.quartz.dataSource.myDS.URL = jdbc:postgresql://localhost:5432/quartz
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = password
org.quartz.dataSource.myDS.maxConnections = 10
org.quartz.dataSource.myDS.connectionProvider.class = org.quartz.utils.HikariCpPoolingConnectionProvider
*/
// HikariCP Connection Pooling Configuration
/*
# Use HikariCP for connection pooling
org.quartz.dataSource.myDS.connectionProvider.class = org.quartz.utils.HikariCpPoolingConnectionProvider
org.quartz.dataSource.myDS.maximumPoolSize = 20
org.quartz.dataSource.myDS.minimumIdle = 5
org.quartz.dataSource.myDS.maxLifetime = 1800000
org.quartz.dataSource.myDS.connectionTimeout = 30000
org.quartz.dataSource.myDS.idleTimeout = 600000
org.quartz.dataSource.myDS.connectionTestQuery = SELECT 1
*/
// C3P0 Connection Pooling Configuration
/*
# Use C3P0 for connection pooling
org.quartz.dataSource.myDS.connectionProvider.class = org.quartz.utils.C3p0PoolingConnectionProvider
org.quartz.dataSource.myDS.maxPoolSize = 20
org.quartz.dataSource.myDS.minPoolSize = 5
org.quartz.dataSource.myDS.initialPoolSize = 10
org.quartz.dataSource.myDS.maxIdleTime = 300
org.quartz.dataSource.myDS.idleConnectionTestPeriod = 3000
org.quartz.dataSource.myDS.validationQuery = SELECT 1
*/
// JNDI Data Source Configuration
/*
# Use JNDI data source
org.quartz.jobStore.dataSource = myJndiDS
org.quartz.dataSource.myJndiDS.connectionProvider.class = org.quartz.utils.JNDIConnectionProvider
org.quartz.dataSource.myJndiDS.jndiURL = java:comp/env/jdbc/QuartzDS
*/
// Programmatic Configuration
Properties props = new Properties();
props.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
props.setProperty("org.quartz.jobStore.dataSource", "myDS");
props.setProperty("org.quartz.jobStore.tablePrefix", "QRTZ_");
props.setProperty("org.quartz.jobStore.isClustered", "true");
// Data source properties
props.setProperty("org.quartz.dataSource.myDS.driver", "org.postgresql.Driver");
props.setProperty("org.quartz.dataSource.myDS.URL", "jdbc:postgresql://localhost:5432/quartz");
props.setProperty("org.quartz.dataSource.myDS.user", "quartz");
props.setProperty("org.quartz.dataSource.myDS.password", "password");
props.setProperty("org.quartz.dataSource.myDS.maxConnections", "15");
props.setProperty("org.quartz.dataSource.myDS.connectionProvider.class",
"org.quartz.utils.HikariCpPoolingConnectionProvider");
SchedulerFactory factory = new StdSchedulerFactory(props);
Scheduler scheduler = factory.getScheduler();
// Custom Connection Provider
public class CustomConnectionProvider implements PoolingConnectionProvider {
private HikariDataSource dataSource;
@Override
public void initialize() throws SQLException {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/quartz");
config.setUsername("quartz");
config.setPassword("password");
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setConnectionTestQuery("SELECT 1");
dataSource = new HikariDataSource(config);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public void shutdown() throws SQLException {
if (dataSource != null) {
dataSource.close();
}
}
@Override
public int getPoolSize() {
return dataSource.getHikariPoolMXBean().getTotalConnections();
}
@Override
public int getMaxPoolSize() {
return dataSource.getMaximumPoolSize();
}
@Override
public int getConnectionsInUse() {
return dataSource.getHikariPoolMXBean().getActiveConnections();
}
}
// Database Schema Creation
// Quartz provides SQL scripts for creating required tables:
// - tables_postgres.sql
// - tables_mysql.sql
// - tables_oracle.sql
// - tables_sqlserver.sql
// - tables_db2.sql
// - tables_h2.sql
// etc.
/*
Example PostgreSQL schema (simplified):
CREATE TABLE 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 BOOL NOT NULL,
is_nonconcurrent BOOL NOT NULL,
is_update_data BOOL NOT NULL,
requests_recovery BOOL NOT NULL,
job_data BYTEA NULL,
PRIMARY KEY (sched_name, job_name, job_group)
);
CREATE TABLE 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 NULL,
prev_fire_time BIGINT NULL,
priority INTEGER NULL,
trigger_state VARCHAR(16) NOT NULL,
trigger_type VARCHAR(8) NOT NULL,
start_time BIGINT NOT NULL,
end_time BIGINT NULL,
calendar_name VARCHAR(200) NULL,
misfire_instr SMALLINT NULL,
job_data BYTEA NULL,
PRIMARY KEY (sched_name, trigger_name, trigger_group)
);
*/
// Monitoring Connection Pools
public void monitorConnectionPool(PoolingConnectionProvider provider) {
System.out.println("Pool Size: " + provider.getPoolSize());
System.out.println("Max Pool Size: " + provider.getMaxPoolSize());
System.out.println("Connections In Use: " + provider.getConnectionsInUse());
System.out.println("Available Connections: " +
(provider.getPoolSize() - provider.getConnectionsInUse()));
}| Database | Delegate Class | Clustering | Notes |
|---|---|---|---|
| PostgreSQL | PostgreSQLDelegate | Yes | Recommended for production |
| MySQL | MySQLDelegate | Yes | Full feature support |
| Oracle | OracleDelegate | Yes | Enterprise features |
| SQL Server | MSSQLDelegate | Yes | Full support |
| DB2 | DB2v7Delegate | Yes | Version 7+ recommended |
| H2 | H2Delegate | Limited | Development/testing |
| HSQLDB | HSQLDBDelegate | No | Development only |
| Apache Derby | CloudscapeDelegate | Limited | Embedded use |
Install with Tessl CLI
npx tessl i tessl/maven-org-quartz-scheduler--quartz