我接到一个需求,要用脚本来查询DB并记录返回条数和耗时。脚本要能做到一次查询,和定时查询。工具配置文件里定义好query和执行次数,每个query执行这么多次后,计算出一个平均耗时。
- 一次查询的话结果写入csv文件,结束。
- 定时查询的话,用户定义好时间点,每天的这个时候开始查询,每次结果append到csv文件里
- 另外给用户一个timeout setting,有时候某个表正在刷新,或者有问题,那么query的时候就需要很久很久都不会返回结果,整个工具就会卡住。所以根据用户的timeout setting,如果一个query超过10分钟还没有返回,结果里记录timeout然后接着跑下一个query
一次查询的话,非常简单。
定时查询的话,用到了org.quartz-scheduler。
第一步,定义一个自己的job类来实现Job接口的execute()方法,这个方法定义了每次执行job的具体步骤。参数JobExecutionContext context非常有用,通过它可以拿到job details还有要传递给job的参数(JobDataMap)。
public class MyOwnJob implements Job
{
public void execute(JobExecutionContext context) throws JobExecutionException
{
...
}
}
JobDataMap datamap = paramJobExecutionContext.getJobDetail().getJobDataMap();
第二步,实现Schedule:使用JobBuilder新建MyOwnJob的实例 >> 将想要传递给MyOwnJob的参数放入JobDataMap >> 用CronExpression建立trigger >> 将JobDetail 实例和trigger加入到scheduler里去
public void ceateJobSchedule(...){
JobDetail jobD = JobBuilder.newJob(MyOwnJob.class).withIdentity(jobName, groupName).build();
jobD.getJobDataMap.put(parameter,value);
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, groupName).withSchedule(CronScheduleBuilder.cronSchedule(cronExp)).build();
scheduler.scheduleJob(jobD, trigger);
scheduler.start()
需要注意的是,到了时间点,Quartz就会起一个线程,新建一个MyOwnJob的实例来执行MyOwnJob.execute()方法。MyOwnJob类里面存结果的属性或者结构不要定义成static的,否则不同线程之间会互相干扰,结果会混在一起…
至于DB query的timeout,一般的DB driver都有timeout设置,偏巧我们用到的这个数据中心自己的build的DB driver没有实现timeout。那好吧,自己动手.
打个比方,DAO里面有一个query(String query)方法,想要给这个方法设置一个timeout,那么,新建一个queryWithTimeoutSetting()方法,在新方法里,创建FutureTask实例,把之前的query()方法包进去,FutureTask.get()执行并捕捉time out exception.
public Integer queryWithTimeoutSetting(int timeOut, String query){
FutureTask<Integer> fTask = new FutureTask<Integer>(
new Callable<Integer>(){
public Integer call() throws SQLException{
return query(String query);
}
}
);
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(fTask);
try{
int result = fTask.get(timeOut, TimeUnit.MINUTES);
} catch (ExecutionException e){
fTask.cancel(true);
} catch (TimeoutException e){
//deal with time out....
fTask.cancel(true);
} finally {
fTask.cancel(true);
executor.shutdown();
return result;
}
}