批处理任务通过quartz控制执行的时候,如果有多个部署,就要避免部署的不同应用上的定时任务同时执行而导致的错误。
通过oracle的行锁,控制quartz的执行。
使用spring+quartz+ibatis
ibatis配置文件中里面的查询,如果发现存在对应的行被锁,直接抛出异常返回,知道当前任务正在执行
<select id="abatorgenerated_selectByExampleForUpdate" resultMap="abatorgenerated_SysRunParamResult" parameterClass="com.huateng.system.entity.SysRunParamExample" >
select id, type, systemId, key, value, createId, createTime, oprId, oprTime, RESERVER1,
RESERVER2, RESERVER3
from HT_SYSRUNPARAM
<isParameterPresent >
<include refid="HT_SYSRUNPARAM.abatorgenerated_Example_Where_Clause" />
<isNotNull property="orderByClause" >
order by $orderByClause$
</isNotNull>
</isParameterPresent>
for update nowait
</select>
提供互斥控制的service层方法
/**
* key对应到定时任务的className全称
* 配置事务
* @param key --用className作为key
* @param interval --获取quartz的执行间隔,单位为毫秒
* @param multiNum --异常情况下,多少次执行后,重新执行
* @return
*/
public boolean localQuartzServiceIsRunning(String key,Long interval,int multiNum){
SysRunParam cur;
try {
cur = sysRunParamDAO.getSysRunParamForUpdate(key);
System.out.println(cur);
} catch (DataAccessException e) {
System.out.println("执行过程冲突,DataAccessException+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
return Boolean.TRUE; //访问报错,说明已经有执行
} catch (ResultListEmptyException e) { //没有数据就初始化数据
System.out.println("ResultListEmptyException");
SysRunParam newParam=new SysRunParam();
newParam.setId("1");
newParam.setKey(key);
newParam.setOprid("system");
newParam.setOprtime(Calendar.getInstance().getTime());
newParam.setType("quartz");
newParam.setValue("ture");
newParam.setCreatetime(Calendar.getInstance().getTime());
newParam.setSystemid("2");
sysRunParamDAO.insert(newParam);
return Boolean.FALSE;//更新后执行
}catch(Exception e){
System.out.println("Exception");
return Boolean.FALSE;
}
String statu=cur.getValue();
Date lastUpdateTime=cur.getOprtime();//上一次执行时间
long executeInterval=System.currentTimeMillis()-lastUpdateTime.getTime();
if(Boolean.parseBoolean(statu)){
//如果长时间没有执行,也该修为执行,避免宕机导致的错误.
if(executeInterval>interval*multiNum){
System.out.println("executeInterval>interval*multiNum");
cur.setValue(Boolean.TRUE+"");
cur.setOprtime(Calendar.getInstance().getTime());
sysRunParamDAO.updateRecord(cur);
return Boolean.FALSE;
}else{
return Boolean.TRUE;
}
}else{ //如果没有执行,先更新状态
cur.setValue(Boolean.TRUE+"");
cur.setOprtime(Calendar.getInstance().getTime());
sysRunParamDAO.updateRecord(cur);
return Boolean.FALSE;
}
}
/**
*定时任务完成以后更新运行状态
* @param key
*/
public void updateLocalQuartzLock(String key){
SysRunParam cur;
try {
cur = sysRunParamDAO.getSysRunParamForUpdate(key);
cur.setValue("false");
cur.setOprtime(Calendar.getInstance().getTime());
sysRunParamDAO.updateRecord(cur);
} catch (DataAccessException e) {
e.printStackTrace();
} catch (ResultListEmptyException e) {
e.printStackTrace();
}
}
定时器类
public class ActivityEffectJob {
/**
*
*/
private static final long serialVersionUID = 1L;
private SysRunParamService sysRunParamService;
/**上一次执行的时间*/
private static long lastExecuteTime=System.currentTimeMillis();
private static final int multiNum=10;
public void start() {
long lastExecuteTimetemp=lastExecuteTime;
lastExecuteTime=System.currentTimeMillis();
if(sysRunParamService.localQuartzServiceIsRunning(MY_CLASS_NAME,System.currentTimeMillis()-lastExecuteTimetemp, multiNum)){
System.out.println(MY_CLASS_NAME+"'s job is running");
return;
}
try {
//works
Thread.sleep(1000);
} catch (Exception e) {
}finally{
sysRunParamService.updateLocalQuartzLock(MY_CLASS_NAME);
lastExecuteTime=System.currentTimeMillis();
System.out.println("finally:"+MY_CLASS_NAME+"'s job is finnished");
}
}
/**
* 当前类名
*/
private static final String MY_CLASS_NAME;
static{
MY_CLASS_NAME = new Object() {
public String getClassName() {
String clazzName = this.getClass().getName();
return clazzName.substring(0, clazzName.lastIndexOf('$'));
}
}.getClassName();
}
public SysRunParamService getSysRunParamService() {
return sysRunParamService;
}
public void setSysRunParamService(SysRunParamService sysRunParamService) {
this.sysRunParamService = sysRunParamService;
}
}
建表脚本
create table HT_SYSRUNPARAM
(
ID VARCHAR2(30),
TYPE VARCHAR2(30),
PARENTTYPE VARCHAR2(30),
SYSTEMID VARCHAR2(30),
KEY VARCHAR2(200),
VALUE VARCHAR2(200),
DSC VARCHAR2(500),
CREATEID VARCHAR2(30),
CREATETIME TIMESTAMP(6),
OPRID VARCHAR2(30),
OPRTIME TIMESTAMP(6),
RESERVER1 VARCHAR2(100),
RESERVER2 VARCHAR2(100),
RESERVER3 VARCHAR2(100)
)
;