zoukankan      html  css  js  c++  java
  • 使用quartz数据库锁实现定时任务的分布式部署

    ,1.根据项目引用的quartz依赖版本,确定下载的quartz-distribution安装包,我项目引用的信息如下图所示;

    2.解压,在quartz-2.2.3-distributionquartz-2.2.3docsdbTables路径下,寻找项目中使用的数据库类型对应的脚本文件,我用的是oracle,脚本信息如下;

    -- delete from qrtz_fired_triggers;
    -- delete from qrtz_simple_triggers;
    -- delete from qrtz_simprop_triggers;
    -- delete from qrtz_cron_triggers;
    -- delete from qrtz_blob_triggers;
    -- delete from qrtz_triggers;
    -- delete from qrtz_job_details;
    -- delete from qrtz_calendars;
    -- delete from qrtz_paused_trigger_grps;
    -- delete from qrtz_locks;
    -- delete from qrtz_scheduler_state;
    -- 
    -- drop table qrtz_calendars;
    -- drop table qrtz_fired_triggers;
    -- drop table qrtz_blob_triggers;
    -- drop table qrtz_cron_triggers;
    -- drop table qrtz_simple_triggers;
    -- drop table qrtz_simprop_triggers;
    -- drop table qrtz_triggers;
    -- drop table qrtz_job_details;
    -- drop table qrtz_paused_trigger_grps;
    -- drop table qrtz_locks;
    -- drop table qrtz_scheduler_state;
    
    
    CREATE TABLE qrtz_job_details
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        JOB_NAME  VARCHAR2(200) NOT NULL,
        JOB_GROUP VARCHAR2(200) NOT NULL,
        DESCRIPTION VARCHAR2(250) NULL,
        JOB_CLASS_NAME   VARCHAR2(250) NOT NULL, 
        IS_DURABLE VARCHAR2(1) NOT NULL,
        IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
        IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
        REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
        JOB_DATA BLOB NULL,
        CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
    );
    CREATE TABLE qrtz_triggers
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        JOB_NAME  VARCHAR2(200) NOT NULL, 
        JOB_GROUP VARCHAR2(200) NOT NULL,
        DESCRIPTION VARCHAR2(250) NULL,
        NEXT_FIRE_TIME NUMBER(13) NULL,
        PREV_FIRE_TIME NUMBER(13) NULL,
        PRIORITY NUMBER(13) NULL,
        TRIGGER_STATE VARCHAR2(16) NOT NULL,
        TRIGGER_TYPE VARCHAR2(8) NOT NULL,
        START_TIME NUMBER(13) NOT NULL,
        END_TIME NUMBER(13) NULL,
        CALENDAR_NAME VARCHAR2(200) NULL,
        MISFIRE_INSTR NUMBER(2) NULL,
        JOB_DATA BLOB NULL,
        CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) 
          REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) 
    );
    CREATE TABLE qrtz_simple_triggers
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        REPEAT_COUNT NUMBER(7) NOT NULL,
        REPEAT_INTERVAL NUMBER(12) NOT NULL,
        TIMES_TRIGGERED NUMBER(10) NOT NULL,
        CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    CREATE TABLE qrtz_cron_triggers
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        CRON_EXPRESSION VARCHAR2(120) NOT NULL,
        TIME_ZONE_ID VARCHAR2(80),
        CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
          REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    CREATE TABLE qrtz_simprop_triggers
      (          
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        STR_PROP_1 VARCHAR2(512) NULL,
        STR_PROP_2 VARCHAR2(512) NULL,
        STR_PROP_3 VARCHAR2(512) NULL,
        INT_PROP_1 NUMBER(10) NULL,
        INT_PROP_2 NUMBER(10) NULL,
        LONG_PROP_1 NUMBER(13) NULL,
        LONG_PROP_2 NUMBER(13) NULL,
        DEC_PROP_1 NUMERIC(13,4) NULL,
        DEC_PROP_2 NUMERIC(13,4) NULL,
        BOOL_PROP_1 VARCHAR2(1) NULL,
        BOOL_PROP_2 VARCHAR2(1) NULL,
        CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
          REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    CREATE TABLE qrtz_blob_triggers
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        BLOB_DATA BLOB NULL,
        CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    CREATE TABLE qrtz_calendars
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        CALENDAR_NAME  VARCHAR2(200) NOT NULL, 
        CALENDAR BLOB NOT NULL,
        CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
    );
    CREATE TABLE qrtz_paused_trigger_grps
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        TRIGGER_GROUP  VARCHAR2(200) NOT NULL, 
        CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
    );
    CREATE TABLE qrtz_fired_triggers 
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        ENTRY_ID VARCHAR2(95) NOT NULL,
        TRIGGER_NAME VARCHAR2(200) NOT NULL,
        TRIGGER_GROUP VARCHAR2(200) NOT NULL,
        INSTANCE_NAME VARCHAR2(200) NOT NULL,
        FIRED_TIME NUMBER(13) NOT NULL,
        SCHED_TIME NUMBER(13) NOT NULL,
        PRIORITY NUMBER(13) NOT NULL,
        STATE VARCHAR2(16) NOT NULL,
        JOB_NAME VARCHAR2(200) NULL,
        JOB_GROUP VARCHAR2(200) NULL,
        IS_NONCONCURRENT VARCHAR2(1) NULL,
        REQUESTS_RECOVERY VARCHAR2(1) NULL,
        CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)
    );
    CREATE TABLE qrtz_scheduler_state 
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        INSTANCE_NAME VARCHAR2(200) NOT NULL,
        LAST_CHECKIN_TIME NUMBER(13) NOT NULL,
        CHECKIN_INTERVAL NUMBER(13) NOT NULL,
        CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
    );
    CREATE TABLE qrtz_locks
      (
        SCHED_NAME VARCHAR2(120) NOT NULL,
        LOCK_NAME  VARCHAR2(40) NOT NULL, 
        CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)
    );
    
    create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);
    create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);
    
    create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
    create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);
    create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);
    create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);
    create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);
    create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);
    create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
    create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
    create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
    create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
    
    create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);
    create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
    create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
    create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);
    create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
    create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);
    
    commit;

    注意,一定要在下面加上commit;原文件是没有的。

    mysql脚本:

    #
    # Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
    #
    # PLEASE consider using mysql with innodb tables to avoid locking issues
    #
    # In your Quartz properties file, you'll need to set 
    # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    
    DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
    DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
    DROP TABLE IF EXISTS QRTZ_LOCKS;
    DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_TRIGGERS;
    DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
    DROP TABLE IF EXISTS QRTZ_CALENDARS;
    
    
    CREATE TABLE QRTZ_JOB_DETAILS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        JOB_NAME  VARCHAR(200) NOT NULL,
        JOB_GROUP VARCHAR(200) NOT NULL,
        DESCRIPTION VARCHAR(250) NULL,
        JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
        IS_DURABLE VARCHAR(1) NOT NULL,
        IS_NONCONCURRENT VARCHAR(1) NOT NULL,
        IS_UPDATE_DATA VARCHAR(1) NOT NULL,
        REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
        JOB_DATA BLOB NULL,
        PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
    );
    
    CREATE TABLE QRTZ_TRIGGERS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        JOB_NAME  VARCHAR(200) NOT NULL,
        JOB_GROUP VARCHAR(200) NOT NULL,
        DESCRIPTION VARCHAR(250) NULL,
        NEXT_FIRE_TIME BIGINT(13) NULL,
        PREV_FIRE_TIME BIGINT(13) NULL,
        PRIORITY INTEGER NULL,
        TRIGGER_STATE VARCHAR(16) NOT NULL,
        TRIGGER_TYPE VARCHAR(8) NOT NULL,
        START_TIME BIGINT(13) NOT NULL,
        END_TIME BIGINT(13) NULL,
        CALENDAR_NAME VARCHAR(200) NULL,
        MISFIRE_INSTR SMALLINT(2) NULL,
        JOB_DATA BLOB NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
            REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
    );
    
    CREATE TABLE QRTZ_SIMPLE_TRIGGERS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        REPEAT_COUNT BIGINT(7) NOT NULL,
        REPEAT_INTERVAL BIGINT(12) NOT NULL,
        TIMES_TRIGGERED BIGINT(10) NOT NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    CREATE TABLE QRTZ_CRON_TRIGGERS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        CRON_EXPRESSION VARCHAR(200) NOT NULL,
        TIME_ZONE_ID VARCHAR(80),
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    CREATE TABLE QRTZ_SIMPROP_TRIGGERS
      (          
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        STR_PROP_1 VARCHAR(512) NULL,
        STR_PROP_2 VARCHAR(512) NULL,
        STR_PROP_3 VARCHAR(512) NULL,
        INT_PROP_1 INT NULL,
        INT_PROP_2 INT NULL,
        LONG_PROP_1 BIGINT NULL,
        LONG_PROP_2 BIGINT NULL,
        DEC_PROP_1 NUMERIC(13,4) NULL,
        DEC_PROP_2 NUMERIC(13,4) NULL,
        BOOL_PROP_1 VARCHAR(1) NULL,
        BOOL_PROP_2 VARCHAR(1) NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    CREATE TABLE QRTZ_BLOB_TRIGGERS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        BLOB_DATA BLOB NULL,
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
            REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    );
    
    CREATE TABLE QRTZ_CALENDARS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        CALENDAR_NAME  VARCHAR(200) NOT NULL,
        CALENDAR BLOB NOT NULL,
        PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
    );
    
    CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        TRIGGER_GROUP  VARCHAR(200) NOT NULL, 
        PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
    );
    
    CREATE TABLE QRTZ_FIRED_TRIGGERS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        ENTRY_ID VARCHAR(95) NOT NULL,
        TRIGGER_NAME VARCHAR(200) NOT NULL,
        TRIGGER_GROUP VARCHAR(200) NOT NULL,
        INSTANCE_NAME VARCHAR(200) NOT NULL,
        FIRED_TIME BIGINT(13) NOT NULL,
        SCHED_TIME BIGINT(13) NOT NULL,
        PRIORITY INTEGER NOT NULL,
        STATE VARCHAR(16) NOT NULL,
        JOB_NAME VARCHAR(200) NULL,
        JOB_GROUP VARCHAR(200) NULL,
        IS_NONCONCURRENT VARCHAR(1) NULL,
        REQUESTS_RECOVERY VARCHAR(1) NULL,
        PRIMARY KEY (SCHED_NAME,ENTRY_ID)
    );
    
    CREATE TABLE QRTZ_SCHEDULER_STATE
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        INSTANCE_NAME VARCHAR(200) NOT NULL,
        LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
        CHECKIN_INTERVAL BIGINT(13) NOT NULL,
        PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
    );
    
    CREATE TABLE QRTZ_LOCKS
      (
        SCHED_NAME VARCHAR(120) NOT NULL,
        LOCK_NAME  VARCHAR(40) NOT NULL, 
        PRIMARY KEY (SCHED_NAME,LOCK_NAME)
    );
    
    
    commit;

    3.建好表后,开始写java代码了,首先是2个配置文件,quartz.properties和spring-quartz.xml,其中spring-quartz.xml要随项目加载启动,可以放在spring启动文件里面或者通过listener启动。

    我是通过在web.xml里

    然后在applicationContext-bean.xml里面设置需要启动加载的xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:task="http://www.springframework.org/schema/task"
        xmlns:cxf="http://cxf.apache.org/core"
        xmlns:jaxws="http://cxf.apache.org/jaxws"
        xmlns:jaxrs="http://cxf.apache.org/jaxrs"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.0.xsd 
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-4.0.xsd 
            http://www.springframework.org/schema/task 
            http://www.springframework.org/schema/task/spring-task-4.0.xsd
            http://cxf.apache.org/core 
            http://cxf.apache.org/schemas/core.xsd
            http://cxf.apache.org/jaxws 
            http://cxf.apache.org/schemas/jaxws.xsd
            http://cxf.apache.org/jaxrs 
            http://cxf.apache.org/schemas/jaxrs.xsd">
            
        <!--===用于解耦框架,启动自定义框架===-->
        <import resource="classpath*:resource/applicationContext-master.xml"/>
        <import resource="classpath*:resource/applicationContext-slaveone-dao.xml"/>
        <import resource="classpath*:resource/applicationContext-slavetwo-dao.xml"/>
        <import resource="classpath*:resource/applicationContext-rmkj-dao.xml"/>
        <import resource="classpath*:resource/applicationContext-quartz.xml"/>
        <import resource="classpath*:resource/applicationContext-thread-pool.xml"/>
        <import resource="classpath*:resource/applicationContext-redis.xml"/>
        <import resource="classpath*:resource/applicationContext-service.xml"/>
        <import resource="classpath*:resource/applicationContext-shiro.xml"/>
        <import resource="classpath*:resource/applicationContext-transaction.xml"/>
        <import resource="classpath*:resource/spring-quartz.xml"/>
    </beans>

    在上面的这些xml里面,最好是第一个加上把所有properties文件加载起来。

    quartz.properties:

    #============================================================================
    # Configure JobStore
    # Using Spring datasource in quartzJobsConfig.xml
    # Spring uses LocalDataSourceJobStore extension of JobStoreCMT
    #============================================================================
    org.quartz.jobStore.useProperties=true
    #quartz存储任务相关数据的表的前缀
    org.quartz.jobStore.tablePrefix = QRTZ_
    #是否启用集群,启用,改为true,注意:启用集群后,必须配置数据源,否则quartz调度器会初始化失败
    org.quartz.jobStore.isClustered = true
    #集群中服务器相互检测间隔,每台服务器都会按照下面配置的时间间隔往服务器中更新自己的状态,如果某台服务器超过以下时间没有checkin,调度器就会认为该台服务器已经down掉,不会再分配任务给该台服务器
    org.quartz.jobStore.clusterCheckinInterval = 5000
    #表示如果某个任务到达执行时间,而此时线程池中没有可用线程时,任务等待的最大时间,如果等待时间超过下面配置的值(毫秒),本次就不在执行,而等待下一次执行时间的到来,可根据任务量和负责程度来调整
    org.quartz.jobStore.misfireThreshold = 60000
    org.quartz.jobStore.txIsolationLevelReadCommitted = true
    #实现集群时,任务的存储实现方式,org.quartz.impl.jdbcjobstore.JobStoreTX表示数据库存储
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    
    
    #============================================================================
    # Configure Main Scheduler Properties
    # Needed to manage cluster instances
    #============================================================================
    #集群中每台服务器自己的id,AUTO表示自动生成
    org.quartz.scheduler.instanceId=AUTO
    #配置集群时,quartz调度器的id,由于配置集群时,只有一个调度器,必须保证每个服务器该值都相同,可以不用修改,只要每个ams都一样就行
    org.quartz.scheduler.instanceName=MY_CLUSTERED_JOB_SCHEDULER
    org.quartz.scheduler.rmi.export = false
    org.quartz.scheduler.rmi.proxy = false
    
    
    #============================================================================
    # Configure ThreadPool
    #============================================================================
    #quartz线程池的实现类
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    #quartz线程池中线程数,可根据任务数量和负责度来调整
    org.quartz.threadPool.threadCount = 10
    #quartz线程优先级
    org.quartz.threadPool.threadPriority = 5
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

    spring-quartz.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.ra.quartz"/>
        <!--如果项目没有配置数据源信息,需配置dataSource信息-->
        <!--
        <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiName" value="/jndi/quartz"/>
        </bean>
        -->
        <!-- 分布式事务配置 start -->
        <!-- 配置线程池-->
        <bean name="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
            <property name="corePoolSize" value="15"/>
            <property name="maxPoolSize" value="25"/>
            <property name="queueCapacity" value="100"/>
        </bean>
    
        <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!-- 配置调度任务-->
        <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="configLocation" value="classpath:resource/quartz.properties"/>
            <property name="dataSource" ref="dataSource"/>
            <property name="transactionManager" ref="transactionManager"/>
    
            <!-- 任务唯一的名称,将会持久化到数据库-->
            <property name="schedulerName" value="baseScheduler"/>
    
            <!-- 每台集群机器部署应用的时候会更新触发器-->
            <property name="overwriteExistingJobs" value="true"/>
            <property name="applicationContextSchedulerContextKey" value="appli"/>
    
            <property name="jobFactory">
                <bean class="com.ra.quartz.AutowiringSpringBeanJobFactory"/>
            </property>
    
            <property name="triggers">
                <list>
                 <!--    <ref bean="printCurrentTimeScheduler"/>
                    <ref bean="tenSecondsScheduler"/> -->
                    <ref bean="calculateTravelInfoScheduler"/>
                    <ref bean="dealPatchTrackScheduler"/>
                    <ref bean="deleteOtherMediaScheduler"/>
                    <ref bean="deleteWeatherScheduler"/>
                    <ref bean="evaluationDriverScheduler"/>
                    <ref bean="reportCreateMonthDataScheduler"/>
                    <ref bean="reportCreateWeekExcelAndImageScheduler"/>
                    <ref bean="reportCreateWeekWordScheduler"/>
                    <!--<ref bean="rMKJFaceIdentityScheduler"/>
                     <ref bean="selectWeatherInfoScheduler"/>
                     --><ref bean="statisticsCarOnlineHighRiskCountScheduler"/>
                    <ref bean="statisticsEveryTimeScheduler"/>
                    <ref bean="sycroRmkjCarInfoScheduler"/>
                    <ref bean="updateDriverSeqNoScheduler"/>
                    <ref bean="updatePBWUserInfoScheduler"/>
                    <ref bean="updateStatusScheduler"/>
                    <ref bean="updateTruckRiskOnTimeBy20secondsScheduler"/>
                </list>
            </property>
            <property name="jobDetails">
                <list>
                  <!--   <ref bean="printCurrentTimeJobs"/>
                    <ref bean="tenSecondsJobs"/> -->
                    <ref bean="calculateTravelInfoJobs"/>
                    <ref bean="dealPatchTrackJobs"/>
                    <ref bean="deleteOtherMediaJobs"/>
                    <ref bean="deleteWeatherJobs"/>
                    <ref bean="evaluationDriverJobs"/>
                    <ref bean="reportCreateMonthDataJobs"/>
                    <ref bean="reportCreateWeekExcelAndImageJobs"/>
                    <ref bean="reportCreateWeekWordJobs"/>
                    <!--<ref bean="rMKJFaceIdentityJobs"/>
                     <ref bean="selectWeatherInfoJobs"/>
                     --><ref bean="statisticsCarOnlineHighRiskCountJobs"/>
                    <ref bean="statisticsEveryTimeJobs"/>
                    <ref bean="sycroRmkjCarInfoJobs"/>
                    <ref bean="updateDriverSeqNoJobs"/>
                    <ref bean="updatePBWUserInfoJobs"/>
                    <ref bean="updateStatusJobs"/>
                    <ref bean="updateTruckRiskOnTimeBy20secondsJobs"/>
                </list>
            </property>
    
            <property name="taskExecutor" ref="executor"/>
    
        </bean>
    
        <!-- 配置Job详情 -->
    <!--     <bean name="printCurrentTimeJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.PrintCurrentTimeJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="tenSecondsJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.TenSecondsJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean> -->
    
        <bean name="calculateTravelInfoJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.CalculateTravelInfoJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="dealPatchTrackJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.DealPatchTrackJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="deleteOtherMediaJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.DeleteOtherMediaJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="deleteWeatherJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.DeleteWeatherJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="evaluationDriverJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.EvaluationDriverJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="reportCreateMonthDataJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.ReportCreateMonthDataJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="reportCreateWeekExcelAndImageJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.ReportCreateWeekExcelAndImageJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="reportCreateWeekWordJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.ReportCreateWeekWordJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
    <!--    <bean name="rMKJFaceIdentityJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.RMKJFaceIdentityJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
         <bean name="selectWeatherInfoJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.SelectWeatherInfoJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean> -->
    
        <bean name="statisticsCarOnlineHighRiskCountJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.StatisticsCarOnlineHighRiskCountJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="statisticsEveryTimeJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.StatisticsEveryTimeJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="sycroRmkjCarInfoJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.SycroRmkjCarInfoJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="updateDriverSeqNoJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.UpdateDriverSeqNoJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="updatePBWUserInfoJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.UpdatePBWUserInfoJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="updateStatusJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.UpdateStatusJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <bean name="updateTruckRiskOnTimeBy20secondsJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="jobClass" value="com.ra.quartz.jobs.UpdateTruckRiskOnTimeBy20secondsJobs"/>
            <property name="durability" value="true"/>
            <property name="requestsRecovery" value="false"/>
        </bean>
    
        <!-- 配置触发时间 -->
      <!--   <bean name="printCurrentTimeScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="printCurrentTimeJobs"/>
            <property name="cronExpression">
                <value>0/5 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="tenSecondsScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="tenSecondsJobs"/>
            <property name="cronExpression">
                <value>0/10 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean> -->
        <bean name="calculateTravelInfoScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="calculateTravelInfoJobs"/>
            <property name="cronExpression">
                <value>0 0 6 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="dealPatchTrackScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="dealPatchTrackJobs"/>
            <property name="cronExpression">
                <value>0/20 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="deleteOtherMediaScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="deleteOtherMediaJobs"/>
            <property name="cronExpression">
                <value>0 0 2 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="deleteWeatherScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="deleteWeatherJobs"/>
            <property name="cronExpression">
                <value>0 03 0/1 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="evaluationDriverScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="evaluationDriverJobs"/>
            <property name="cronExpression">
                <value>0 0 22 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="reportCreateMonthDataScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="reportCreateMonthDataJobs"/>
            <property name="cronExpression">
                <value>0 15 1 1 * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="reportCreateWeekExcelAndImageScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="reportCreateWeekExcelAndImageJobs"/>
            <property name="cronExpression">
                <value>0 0 2 ? * MON</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="reportCreateWeekWordScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="reportCreateWeekWordJobs"/>
            <property name="cronExpression">
                <value>0 0 4 ? * MON</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
    <!--     <bean name="rMKJFaceIdentityScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="rMKJFaceIdentityJobs"/>
            <property name="cronExpression">
                <value>0/5 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean> -->
    <!--     <bean name="selectWeatherInfoScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="selectWeatherInfoJobs"/>
            <property name="cronExpression">
                <value>0/5 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean> -->
        <bean name="statisticsCarOnlineHighRiskCountScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="statisticsCarOnlineHighRiskCountJobs"/>
            <property name="cronExpression">
                <value>0/60 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="statisticsEveryTimeScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="statisticsEveryTimeJobs"/>
            <property name="cronExpression">
                <value>0 03 0/1 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="sycroRmkjCarInfoScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="sycroRmkjCarInfoJobs"/>
            <property name="cronExpression">
                <value>0 0/2 * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="updateDriverSeqNoScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="updateDriverSeqNoJobs"/>
            <property name="cronExpression">
                <value>0 0 0 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="updatePBWUserInfoScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="updatePBWUserInfoJobs"/>
            <property name="cronExpression">
                <value>0 55 18 14 * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="updateStatusScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="updateStatusJobs"/>
            <property name="cronExpression">
                <value>0 0 1 * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <bean name="updateTruckRiskOnTimeBy20secondsScheduler" class="com.ra.quartz.PersistableCronTriggerFactoryBean">
            <property name="jobDetail" ref="updateTruckRiskOnTimeBy20secondsJobs"/>
            <property name="cronExpression">
                <value>0/10 * * * * ?</value>
            </property>
            <property name="timeZone">
                <value>GMT+8:00</value>
            </property>
        </bean>
        <!-- 分布式事务配置 end -->
    </beans>

    4.编码AutowiringSpringBeanJobFactory类,作用是:使用@autowire来自动装配类

    package com.ra.quartz;
    
    import org.quartz.spi.TriggerFiredBundle;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.scheduling.quartz.SpringBeanJobFactory;
    
    /**
     * @Auther: lanhao
     * @Date: 2018/8/14 11:37
     * @Description:
     */
    public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
        private transient AutowireCapableBeanFactory beanFactory;
    
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            beanFactory = applicationContext.getAutowireCapableBeanFactory();
        }
    
    
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            Object job = super.createJobInstance(bundle);
            beanFactory.autowireBean(job);
            return job;
        }
    }

    5.编写PersistableCronTriggerFactoryBean类

    package com.ra.quartz;
    
    import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
    
    import java.text.ParseException;
    
    /**
     * @Auther: lanhao
     * @Date: 2018/8/14 14:06
     * @Description:
     */
    public class PersistableCronTriggerFactoryBean extends CronTriggerFactoryBean{
        @Override
        public void afterPropertiesSet() throws ParseException
        {
            super.afterPropertiesSet();
            getJobDataMap().remove(getObject().getJobKey().getName());
        }
    }

    6.下面就是具体的job类了,以其中一个例子为类;

    UpdateStatusJobs:

    package com.ra.quartz.jobs;
    
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    
    import com.ra.quartz.UpdateStatusQuartz;
    
    public class UpdateStatusJobs extends QuartzJobBean{
    
        @Autowired
        private UpdateStatusQuartz clusterQuartz;
        
        @Override
        protected void executeInternal(JobExecutionContext context)
                throws JobExecutionException {
            clusterQuartz.updateStatus(); 
        }
    
    }

    注:@Autowired注解能用就是因为上面的AutowiringSpringBeanJobFactory类。

    UpdateStatusQuartz类就是具体的业务逻辑代码了,里面写的方法全部在job里面调用就行了。

    一个定时任务一个job类。

  • 相关阅读:
    [NOIP2013] 提高组 洛谷P1979 华容道
    Vijos P1404 遭遇战
    CodeVS 1506 传话
    P1546 最短网络 Agri-Net
    HDU 4747 Mex
    POJ1020 Anniversary Cake
    【数据结构】平衡二叉树
    【数据结构】二叉排序树
    【数据结构】二叉树
    概念源于生活
  • 原文地址:https://www.cnblogs.com/lazyInsects/p/9492493.html
Copyright © 2011-2022 走看看