Java实现每天定时对数据库操作

现在有一个很棘手的问题:客户要求实现一个功能,就是每日凌晨自动计算慢性病订单是否有需要在今日提醒的,如果有则生成一条提醒记录到lm_notice之中。

如何在Web工程中实现任务计划调度,好多朋友用过Windows的任务计划。经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent  event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):

 private  java.util.Timer  timer  =  null;
   public  void  contextInitialized(ServletContextEvent  event)  {
        timer  =  new  java.util.Timer(true);
        event.getServletContext().log("定时器已启动");
        timer.schedule(new  MyTask(event.getServletContext()),  0,  60*60*1000);
       event.getServletContext().log("已经添加任务调度表");
       }
  public  void  contextDestroyed(ServletContextEvent  event)  {
       timer.cancel();
       event.getServletContext().log("定时器销毁");
       }    

以上代码中, timer.schedule(new  MyTask(event.getServletContext()),  0,  60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:

private  tatic  final  int  C_SCHEDULE_HOUR      =  0;
Private  static  boolean  isRunning  =  false;
Private  ServletContext  context  =  null;
public  MyTask(ServletContext  context)  {
      this.context  =  context;
    }
public  void  run()  {
   Calendar  cal  =  Calendar.getInstance();
   if  (!isRunning)    {
        if  (C_SCHEDULE_HOUR  ==  cal.get(Calendar.HOUR_OF_DAY))  {
             isRunning  =  true;
              context.log("开始执行指定任务");    

             //TODO  添加自定义的详细任务,以下只是示例
             int  i  =  0;
             while  (i++  <  10)  {
             context.log("已完成任务的"  +  i  +  "/"  +  10);
             }    

            isRunning  =  false;
            context.log("指定任务执行结束");
            }
        }  else  {
      context.log("上一次任务执行还未结束");
      }
 }    

上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:

       <listener>
               <listener-class>com.test.ContextListener</listener-class>
       </listener>    

当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

2003-12-05  0:21:39  开始执行指定任务

2003-12-05  0:21:39  已完成任务的1/10

……

2003-12-05  0:21:39  已完成任务的10/10

2003-12-05  0:21:39  指定任务执行结束

Java进阶(十四)实现每天定时对数据库的操作的更多相关文章

  1. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  2. Java线程间通信方式剖析——Java进阶(四)

    原创文章,同步发自作者个人博客,转载请在文章开头处以超链接注明出处 http://www.jasongj.com/java/thread_communication/ CountDownLatch C ...

  3. “全栈2019”Java第九十四章:局部内部类详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  4. “全栈2019”Java第十四章:二进制、八进制、十六进制

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. “全栈2019”Java第二十四章:流程控制语句中决策语句switch下篇

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. Python进阶(十四)----空间角度研究类,类与类之间的关系

    Python进阶(十四)----空间角度研究类,类与类之间的关系 一丶从空间角度研究类 对象操作对象属性 class A(): address = '沙河' def __init__(self, na ...

  7. J2EE进阶(十五)MyEclipse反向工程实现从数据库反向生成实体类之Hibernate方式

    J2EE进阶(十五)MyEclipse反向工程实现从数据库反向生成实体类之Hibernate方式   反向工程又称逆向工程.   开发项目涉及到的表太多,一个一个的写JAVA实体类很是费事.MyEcl ...

  8. Java进阶SQL函数、网页定时刷新与自定义JSTL函数

    一.SQL函数 能够在SQL语句中调用的函数(方法) ,用来实现一些小功能 聚合函数 能够把多行数据聚合成一个值(统计) count()    计数,计算数据条数 max()      计算最大值 m ...

  9. 菜鸟学Java(十四)——Java反射机制(一)

    说到反射,相信有过编程经验的人都不会陌生.反射机制让Java变得更加的灵活.反射机制在Java的众多特性中是非常重要的一个.下面就让我们一点一点了解它是怎么一回事. 什么是反射 在运行状态中,对于任意 ...

随机推荐

  1. mongo 存储过程

    摘要 本文主要介绍mongo存储过程,mongo 存储过程其实就是JS方法,然后通过eval 方法来执行,但是这个方法在3.0 depreate了,也就是在未来的版本,这个功能可能不提供了.从目前的j ...

  2. 在java程序中实现发送邮件的功能

    最近比较忙,在做一个人事管理系统的项目,在这项目需求中,需要一个发送邮件的功能.这个时候我们可以使用javamail的jar包来实现完美需要的功能,在这里简单的分享一个最基础的发邮件功能. 首先我们需 ...

  3. uboot-tiny4412启动流程(下)----如何将自己的裸板测试程序加入uboot中启动测试

    今天在工作上搞了一天高通的芯片uboot程序,目的是希望将一个裸板的程序移植到uboot中,并且开机让它运行.这个芯片是NXP4330,目前是高通的一个芯片,基于ARM-contexA9架构,那么就跟 ...

  4. protobuf中的枚举缺省值应该为UNKNOWN

    protobuf中的枚举缺省值应该为UNKNOWN(金庆的专栏)proto3中的枚举值为了与proto2兼容,要求缺省值固定为第1个,值为0.proto2中并没有规定对范围之外的枚举值的处理,而pro ...

  5. Android Studio下多渠道打包

    Android Studio下实现多渠道打包 直接上步骤 步骤 1. 清单文件添加属性(以友盟统计为例) 在application标签下添加meta-data属性 <application -- ...

  6. Dynamics CRM2016 Web API之Create related entities in one operation

    本篇继续来介绍两个web api的接口,一个是"Create related entities in one operation"即在一步操作中完成主实体的创建加关联实体的创建,一 ...

  7. EBS业务学习之采购管理

    一.基础数据 w供应商档案 w采购员设置 w审批层次 w单据控制 w危险类代码 w检验代码 w自动来源 w供应商项目w目录册 二.业务流程 w请购单 w询价单 w报价单 w采购定单 w接收 w检验 w ...

  8. 操作系统服务:OS模块

    http://blog.csdn.net/pipisorry/article/details/52454486 一般的操作系统服务之OS模块Generic Operating System Servi ...

  9. Eclipse开发C/C++ 安装配置

    1.       jdk环境配置 2.       eclipse 下载 3.       MinGW 下载安装 4.       编写Hello Word jdk环境配置 环境配置我就不多说了,网上 ...

  10. PLSQL解析XML文件

     参考网上资料学习汇总 在PL/SQL中利用XML ,Oracle提供了几个组件,让开发人员能轻松地利用XML技术.这些组件包括: 1.  XML 分析程序.即用来分析.构造和验证XML文档.. ...