소개
Quartz Scheduler는 Java 애플리케이션에서 주기적 또는 일정 시간에 작업을 실행할 수 있는 강력한 도구입니다. 하지만 여러 개의 애플리케이션 인스턴스가 동일한 작업을 동시에 실행하면 문제가 발생할 수 있습니다. 이러한 상황에서 데이터베이스 잠금 제어를 이용하여 작업의 실행을 제어할 수 있습니다. 이 글에서는 Quartz Scheduler와 데이터베이스 잠금 제어를 연동하는 방법을 알아보겠습니다.
Quartz Scheduler 설정
먼저 Quartz Scheduler를 설정해야 합니다. 아래는 간단한 Quartz Scheduler 설정 파일의 예시입니다.
Properties props = new Properties();
props.put("org.quartz.scheduler.instanceName", "QuartzScheduler");
props.put("org.quartz.threadPool.threadCount", "1");
props.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.put("org.quartz.jobStore.dataSource", "myDS");
props.put("org.quartz.dataSource.myDS.driver", "com.mysql.jdbc.Driver");
props.put("org.quartz.dataSource.myDS.URL", "jdbc:mysql://localhost/quartz");
props.put("org.quartz.dataSource.myDS.user", "root");
props.put("org.quartz.dataSource.myDS.password", "password");
props.put("org.quartz.dataSource.myDS.maxConnections", "5");
SchedulerFactory schedulerFactory = new StdSchedulerFactory(props);
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
위 설정 예시에서는 JobStoreTX
를 사용하고, 데이터베이스는 MySQL을 사용합니다.
데이터베이스 잠금 제어 설정
다음으로 데이터베이스에서 잠금을 제어하기 위해 테이블을 생성해야 합니다. Quartz Scheduler는 작업을 제어하기 위해 QRTZ_LOCKS
테이블을 사용합니다. 아래는 MySQL 데이터베이스에서 사용할 수 있는 QRTZ_LOCKS
테이블의 스키마 예시입니다.
create table QRTZ_LOCKS
(
SCHED_NAME varchar(120) not null,
LOCK_NAME varchar(40) not null,
PRIMARY KEY (SCHED_NAME, LOCK_NAME)
);
이제 Quartz Scheduler와 데이터베이스 잠금 제어를 연동할 준비가 되었습니다.
작업 실행 시 잠금 획득
Quartz Scheduler에서 작업을 실행하기 전에 잠금을 획득해야 합니다. 이는 다음과 같이 Job
클래스의 execute()
메서드에서 수행할 수 있습니다.
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 잠금 획득
boolean lockAcquired = false;
Connection connection = null;
try {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobName = (String) dataMap.get("jobName");
// 데이터베이스 연결
DataSource dataSource = (DataSource) context.getScheduler().getContext().get("myDS");
connection = dataSource.getConnection();
// 잠금 획득 시도
lockAcquired = tryAcquireLock(connection, jobName);
if (!lockAcquired) {
// 잠금 획득 실패 시 작업 종료
return;
}
// 작업 실행 로직 작성
// ...
} catch (Exception e) {
// 예외 처리
} finally {
// 잠금 해제
if (lockAcquired) {
releaseLock(connection);
}
// 데이터베이스 연결 해제
if (connection != null) {
connection.close();
}
}
}
private boolean tryAcquireLock(Connection connection, String jobName) throws SQLException {
PreparedStatement ps = connection.prepareStatement("INSERT INTO QRTZ_LOCKS(SCHED_NAME, LOCK_NAME) VALUES (?, ?)");
ps.setString(1, "QuartzScheduler");
ps.setString(2, jobName);
int result = ps.executeUpdate();
ps.close();
return result == 1;
}
private void releaseLock(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement("DELETE FROM QRTZ_LOCKS WHERE SCHED_NAME = ?");
ps.setString(1, "QuartzScheduler");
ps.executeUpdate();
ps.close();
}
}
위 코드에서 tryAcquireLock()
메서드는 잠금을 획득하는 메서드이고, releaseLock()
메서드는 잠금을 해제하는 메서드입니다. 이렇게 작업 실행 전후에 잠금을 제어하여 작업을 동시에 실행하지 않도록 할 수 있습니다.
결론
이제 Quartz Scheduler와 데이터베이스 잠금 제어를 연동하는 방법에 대해서 알아보았습니다. 이를 통해 여러 개의 애플리케이션 인스턴스에서 동시에 작업을 실행할 때 발생할 수 있는 문제를 방지할 수 있습니다.