我接到一個需求,要用腳本來查詢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;
}
}