将任务持久化到数据中。因为集群中节点依赖于来传播Scheduler实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。
org.quartz.jobStore.isClustered 属性为 true,通知Scheduler实例要它参与到一个集群当中。weblogic连接scan ip
org.quartz.jobStore.clusterCheckinInterval
属性定义了Scheduler 实例检入到中的频率(单位:毫秒)。
Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;
这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。
通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)
集群实现分析
Quartz原来码分析:
基于表锁实现多Quartz_Node 对Job,Trigger,Calendar等同步机制
-- 锁定表 CREATE TABLE `QRTZ_LOCKS` ( `LOCK_NAME` varchar(40) NOT NULL, PRIMARY KEY (`LOCK_NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 记录 +-----------------+ | LOCK_NAME | +-----------------+ | CALENDAR_ACCESS | | JOB_ACCESS | | MISFIRE_ACCESS | | STATE_ACCESS | | TRIGGER_ACCESS | +-----------------+
通过行级别锁实现多节点处理
/**
* Internal database based lock handler for providing thread/resource locking
* in order to protect resources from being altered by multiple threads at the
* same time.
*
* @author jhouse
*/
public class StdRowLockSemaphore extends DBSemaphore {
/*
* Constants.
* 锁定SQL语句
*
*/
public static final String SELECT_FOR_LOCK = "SELECT * FROM "
+ TABLE_PREFIX_SUBST + TABLE_LOCKS + " WHERE " + COL_LOCK_NAME
+ " = ? FOR UPDATE";
/**
* This constructor is for using the <code>StdRowLockSemaphore</code> as
* a bean.
*/
public StdRowLockSemaphore() {
super(DEFAULT_TABLE_PREFIX, null, SELECT_FOR_LOCK);
}
public StdRowLockSemaphore(String tablePrefix, String seletWithLockSQL) {
super(tablePrefix, selectWithLockSQL, SELECT_FOR_LOCK);
}
/**
* Execute the SQL select for update that will lock the proper database row.
* 指定锁定SQL
*/
protected void executeSQL(Connection conn, String lockName, String expandedSQL) throws LockException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(expandedSQL);
ps.setString(1, lockName);
if (getLog().isDebugEnabled()) {
getLog().debug(
"Lock '" + lockName + "' is being obtained: " +
Thread.currentThread().getName());
}
rs = ps.executeQuery();
if (!rs.next()) {
throw new SQLException(Util.rtp(
"No row exists in table " + TABLE_PREFIX_SUBST +
TABLE_LOCKS + " for lock named: " + lockName, getTablePrefix()));
}
} catch (SQLException sqle) {
if (getLog().isDebugEnabled()) {
getLog().debug(
"Lock '" + lockName + "' was not obtained by: " +
Thread.currentThread().getName());
}
throw new LockException("Failure obtaining db row lock: "
+ sqle.getMessage(), sqle);
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception ignore) {
}
}
if (ps != null) {
try {
ps.close();
} catch (Exception ignore) {
}
}
}
}
protected String getSelectWithLockSQL() {
return getSQL();
}
public void setSelectWithLockSQL(String selectWithLockSQL) {
setSQL(selectWithLockSQL);
}
}
/**
* Grants a lock on the identified resource to the calling thread (blocking
* until it is available).
* 获取QRTZ_LOCKS行级锁
* @return true if the lock was obtained.
*/
public boolean obtainLock(Connection conn, String lockName) throws LockException {
lockName = lockName.intern();
Logger log = getLog();
if(log.isDebugEnabled()) {
log.debug(
"Lock '" + lockName + "' is desired by: "
+ Thread.currentThread().getName());
}
if (!isLockOwner(conn, lockName)) {
executeSQL(conn, lockName, expandedSQL);
if(log.isDebugEnabled()) {
log.debug(
"Lock '" + lockName + "' given to: "
+ Thread.currentThread().getName());
}
getThreadLocks().add(lockName);
//getThreadLocksObtainer().put(lockName, new
// Exception("Obtainer..."));
} else if(log.isDebugEnabled()) {
log.debug(
"Lock '" + lockName + "' Is already owned by: "
+ Thread.currentThread().getName());
}
return true;
}
/**
* Release the lock on the identified resource if it is held by the calling thread.
* 释放QRTZ_LOCKS行级锁
*/
public void releaseLock(Connection conn, String lockName) {
lockName = lockName.intern();
if (isLockOwner(conn, lockName)) {
if(getLog().isDebugEnabled()) {
getLog().debug(
"Lock '" + lockName + "' returned by: "
+ Thread.currentThread().getName());
}
getThreadLocks().remove(lockName);
//getThreadLocksObtainer().remove(lockName);
} else if (getLog().isDebugEnabled()) {
getLog().warn(
"Lock '" + lockName + "' attempt to return by: "
+ Thread.currentThread().getName()
+ " -- but not owner!",
new Exception("stack-trace of wrongful returner"));
}
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-29777-16.html
以挽回面子