#############################################################################################################################################

 1、 建立数据库11张表

#############################################################################################################################################

先在数据库中建立quartz需要的11张表(我这里用的是Oracle数据库),根据不同的数据库quartz分别提供了不同的初始化sql文件,sql文件路径在 quartz-2.3.0-SNAPSHOT-0724\src\org\quartz\impl\jdbcjobstore下:

 tables_cloudscape.sql
tables_cubrid.sql
tables_db2.sql
tables_db2_v8.sql
tables_db2_v72.sql
tables_db2_v95.sql
tables_derby.sql
tables_derby_previous.sql
tables_firebird.sql
tables_h2.sql
tables_hsqldb.sql
tables_hsqldb_old.sql
tables_informix.sql
tables_mysql.sql
tables_mysql_innodb.sql
tables_oracle.sql
tables_pointbase.sql
tables_postgres.sql
tables_sapdb.sql
tables_solid.sql
tables_sqlServer.sql
tables_sybase.sql

#############################################################################################################################################

 2、 配置定时器数据库等相关配置:quartz.properties

#############################################################################################################################################

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
#调度器实例名称
org.quartz.scheduler.instanceName: SchedulerJoyce0725
org.quartz.scheduler.instanceId: InstanceJoyce0725 #============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 5
org.quartz.threadPool.threadPriority: 1 #============================================================================
# 配置Oracle数据库,命名dataSource为myDS
#============================================================================
### 支持PostgreSQL数据库
###org.quartz.dataSource.myDS.driver=org.postgresql.Driver
###org.quartz.dataSource.myDS.URL=jdbc:postgresql://localhost:5432/quartz
org.quartz.dataSource.myDS.driver=oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL=jdbc:oracle:thin:@localhost:1521:orcl
org.quartz.dataSource.myDS.user=zhuwen
org.quartz.dataSource.myDS.password=ZHUwen12
org.quartz.dataSource.myDS.maxConnections=5
org.quartz.dataSource.myDS.validationQuery=select 0 FROM DUAL #============================================================================
# 配置job任务存储策略,指定一个叫myDS的dataSource
#============================================================================
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
### 支持PostgreSQL数据库
###org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
### 支持Oracle数据库
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true

################################################################################################################

3、 11张表不同定时方式分别存储了不同数据到不同的表

################################################################################################################

ScheduleBuilder是trigger触发器的触发规则定制类,旗下有4种触发器实现类:  CalendarIntervalScheduleBuilder、CronScheduleBuilder、DailyTimeIntervalScheduleBuilder、SimpleScheduleBuilder。

这里演示了CronScheduleBuilder和SimpleScheduleBuilder两种定时方式,分别执行后面的StoreSimpleTrigger2OracleExample.java 和 StoreCronTrigger2OracleExample.java 就能看到数据库如下的差别:

这4中实现类在数据库的11张表中存储一个任务时,分别会产生不一样的数据,用颜色标注insert语句如下:

select * from qrtz_blob_triggers;   --没有insert语句就表示此表一直没有数据

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_calendars;
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_cron_triggers;

Insert into QRTZ_CRON_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,CRON_EXPRESSION,TIME_ZONE_ID)
values ('SchedulerJoyce0725','cronTrigger','cronGroup1','0/5 * * * * ?','Asia/Shanghai');

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_fired_triggers;
Insert into QRTZ_FIRED_TRIGGERS (SCHED_NAME,ENTRY_ID,TRIGGER_NAME,TRIGGER_GROUP,INSTANCE_NAME,FIRED_TIME,SCHED_TIME,PRIORITY,STATE,JOB_NAME,JOB_GROUP,IS_NONCONCURRENT,REQUESTS_RECOVERY)
values ('SchedulerJoyce0725','InstanceJoyce07251564061848994','cronTrigger','cronGroup1','InstanceJoyce0725',1564061855002,1564061855000,5,'EXECUTING','simpleRecoveryJob','cronGroup1','0','0');  --每一次远程启动时ENTRY_ID总是会变一变

Insert into QRTZ_FIRED_TRIGGERS (SCHED_NAME,ENTRY_ID,TRIGGER_NAME,TRIGGER_GROUP,INSTANCE_NAME,FIRED_TIME,SCHED_TIME,PRIORITY,STATE,JOB_NAME,JOB_GROUP,IS_NONCONCURRENT,REQUESTS_RECOVERY) values ('SchedulerJoyce0725','InstanceJoyce07251564066439267','simpleTriger1','simpleGroup','InstanceJoyce0725',1564066446293,1564066451270,5,'ACQUIRED',null,null,'0','0');

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_job_details;
Insert into QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP,DESCRIPTION,JOB_CLASS_NAME,IS_DURABLE,IS_NONCONCURRENT,IS_UPDATE_DATA,REQUESTS_RECOVERY,JOB_DATA)
values ('SchedulerJoyce0725','simpleRecoveryJob','cronGroup1',null,'org.quartz.examples.example15.SimpleRecoveryJob','0','0','0','0',
TO_BLOB(HEXTORAW('...'))|| TO_BLOB(HEXTORAW('...')));

Insert into QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP,DESCRIPTION,JOB_CLASS_NAME,IS_DURABLE,IS_NONCONCURRENT,IS_UPDATE_DATA,REQUESTS_RECOVERY,JOB_DATA)
values ('SchedulerJoyce0725','simpleJob1','simpleGroup',null,'org.quartz.examples.example15.SimpleRecoveryJob','0','0','0','1',
TO_BLOB(HEXTORAW('...'))|| TO_BLOB(HEXTORAW('...')));

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_locks;
Insert into qrtz_locks (SCHED_NAME,LOCK_NAME) values ('SchedulerJoyce0725','STATE_ACCESS');
Insert into qrtz_locks (SCHED_NAME,LOCK_NAME) values ('SchedulerJoyce0725','TRIGGER_ACCESS');

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_paused_trigger_grps;

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_scheduler_state;
Insert into qrtz_scheduler_state (SCHED_NAME,INSTANCE_NAME,LAST_CHECKIN_TIME,CHECKIN_INTERVAL)
values ('SchedulerJoyce0725','InstanceJoyce0725',1564061857522,7500);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_simple_triggers;

Insert into QRTZ_SIMPLE_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,REPEAT_COUNT,REPEAT_INTERVAL,TIMES_TRIGGERED)

values ('SchedulerJoyce0725','simpleTriger1','simpleGroup',20,5000,2);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
select * from qrtz_simprop_triggers;

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_triggers;
Insert into qrtz_triggers (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,JOB_NAME,JOB_GROUP,DESCRIPTION,NEXT_FIRE_TIME,PREV_FIRE_TIME,PRIORITY,TRIGGER_STATE,TRIGGER_TYPE,START_TIME,END_TIME,CALENDAR_NAME,MISFIRE_INSTR,JOB_DATA)
values ('SchedulerJoyce0725','cronTrigger','cronGroup1','simpleRecoveryJob','cronGroup1',null,1564061865000,1564061860000,5,'ACQUIRED','CRON',1564061849000,0,null,0, EMPTY_BLOB());

Insert into QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,JOB_NAME,JOB_GROUP,DESCRIPTION,NEXT_FIRE_TIME,PREV_FIRE_TIME,PRIORITY,TRIGGER_STATE,TRIGGER_TYPE,START_TIME,END_TIME,CALENDAR_NAME,MISFIRE_INSTR,JOB_DATA) values ('SchedulerJoyce0725','simpleTriger1','simpleGroup','simpleJob1','simpleGroup',null,1564066451270,1564066446270,5,'ACQUIRED','SIMPLE',1564066441270,0,null,0, EMPTY_BLOB());

#############################################################################################################################################

4、  job任务类,SimpleRecoveryJob.java

#############################################################################################################################################

package org.quartz.examples.example15;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.Date; /**
* 一个job作业。
*/
public class SimpleRecoveryJob implements Job { private static Logger LOG = LoggerFactory.getLogger(SimpleRecoveryJob.class); private static final String COUNT = "count"; //必须要有public修饰的无参构造函数
public SimpleRecoveryJob() {
} //任务执行方法
public void execute(JobExecutionContext context) throws JobExecutionException { JobKey jobKey = context.getJobDetail().getKey(); // 如果由于“恢复”情况而重新执行作业,此方法将返回true。
if (context.isRecovering()) {
LOG.info("恢复作业:SimpleRecoveryJob: " + jobKey + " RECOVERING at " + new Date());
} else {
LOG.info("不恢复作业:SimpleRecoveryJob: " + jobKey + " starting at " + new Date());
} JobDataMap data = context.getJobDetail().getJobDataMap();
int count;
if (data.containsKey(COUNT)) {
count = data.getInt(COUNT);
} else {
count = 0;
}
count++;
data.put(COUNT, count); LOG.info("SimpleRecoveryJob: " + jobKey + " done at " + new Date() + "\n Execution #" + count); } }

#############################################################################################################################################

5、  简单定时任务存储到数据库表,StoreSimpleTrigger2OracleExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

import static org.quartz.DateBuilder.futureDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger; import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 简单定时任务存储到数据库表。
* 存储job任务到数据库,这里打印的job任务都是: 不恢复作业……
*/
public class StoreSimpleTrigger2OracleExample { private static Logger LOG = LoggerFactory.getLogger(StoreSimpleTrigger2OracleExample.class); public void run(boolean inClearJobs, boolean inScheduleJobs) throws Exception { // 初始化调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler(); if (inClearJobs) {
sched.clear();
LOG.warn("***** Deleted existing jobs/triggers *****");
} LOG.info("------- Initialization Complete -----------"); if (inScheduleJobs) { LOG.info("------- Scheduling Jobs ------------------"); String schedId = sched.getSchedulerInstanceId(); // ========================================================
// ============ job1
// ========================================================
int count = 1;
JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity("simpleJob" + count, "simpleGroup").requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
SimpleTrigger trigger = newTrigger().withIdentity("simpleTriger" + count, "simpleGroup")
.startAt(futureDate(1, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " and repeat: "
+ trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");
sched.scheduleJob(job, trigger);
//
// // ========================================================
// // ============ job2
// // ========================================================
// count++;
// job = newJob(SimpleRecoveryJob.class).withIdentity("job0724_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
// .build();
// trigger = newTrigger().withIdentity("triger0724_" + count, schedId).startAt(futureDate(2, IntervalUnit.SECOND))
// .withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();
// LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " and repeat: "
// + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");
// sched.scheduleJob(job, trigger); } LOG.info("------- Starting Scheduler ---------------");
sched.start();
try {
Thread.sleep(3600L * 1000L);
} catch (Exception e) {
//
}
sched.shutdown();
LOG.info("------- Shutdown Complete ----------------");
} public static void main(String[] args) throws Exception {
boolean clearJobs = true; // 是否清空job任务
boolean scheduleJobs = true; // 是否调度任务 for (String arg : args) {
if (arg.equalsIgnoreCase("clearJobs")) {
clearJobs = true;
} else if (arg.equalsIgnoreCase("dontScheduleJobs")) {
scheduleJobs = false;
}
} StoreSimpleTrigger2OracleExample example = new StoreSimpleTrigger2OracleExample();
example.run(clearJobs, scheduleJobs);
}
}

#############################################################################################################################################

         6、  cron定义定时任务存储到数据库表,StoreCronTrigger2OracleExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger; import java.util.Date; import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* cron定义定时任务存储到数据库表。
* 存储job任务到数据库,这里打印的job任务都是: 不恢复作业……
*/
public class StoreCronTrigger2OracleExample { private static Logger LOG = LoggerFactory.getLogger(StoreCronTrigger2OracleExample.class); public void run(boolean inClearJobs) throws Exception { // 初始化调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler(); if (inClearJobs) {
sched.clear();
LOG.warn("***** Deleted existing jobs/triggers *****");
} // ========================================================
// ============ job1 每20秒执行一次,无限期重复
// ========================================================
JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity("simpleRecoveryJob_Recovery", "cronGroup2")
.requestRecovery() //如果job任务所在服务宕机了或由于其它原因job任务被中断,请标记JobExecutionContext.isRecovering()=true。
//让我可以拿这个标记知道怎么去适配业务场景。
//但是只有恢复任务后首次执行任务时,拿到Recovering标记值为true,此后该任务Recovering值又标记为了false。
.build();
//每5秒执行一次
CronTrigger trigger = newTrigger().withIdentity("cronTrigger_Recovery", "cronGroup2").withSchedule(cronSchedule("0/5 * * * * ?")).build();
Date ft = sched.scheduleJob(job, trigger);
LOG.info(job.getKey() + " has been scheduled to run at: " + ft + " and repeat based on expression: "
+ trigger.getCronExpression()); LOG.info("------- Starting Scheduler ---------------");
sched.start();
try {
Thread.sleep(3600L * 1000L);
} catch (Exception e) {
//
} // 暂停执行任务
sched.pauseJob(job.getKey());
LOG.info("调度器暂停执行定时器,主线程睡眠11秒!!!!会错过执行job1的N次定时任务。模拟当定时器的执行线程由于抢不到CPU时间或其他事件错过执行的情况。");
Thread.sleep(11L * 1000L);
// 继续执行任务
sched.resumeJob(job.getKey()); //当定时器得到继续执行的命令时,被错过执行的任务次数,就会按照misfire的定义去执行 sched.shutdown();
LOG.info("------- Shutdown Complete ----------------");
} public static void main(String[] args) throws Exception {
boolean clearJobs = false; // 是否清空job任务 StoreCronTrigger2OracleExample example = new StoreCronTrigger2OracleExample();
example.run(clearJobs);
}
}

#############################################################################################################################################

7、  执行数据库中的定时任务,RunOracleExistingJobExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 先运行ClusterExample.java,确定Oracle数据库中已存在job任务.
* 这里打印的job任务都是从数据库表里恢复回来的,所以这些任务的第一次执行会打印: 恢复作业……
* 此后job任务就只打印:不恢复作业……
*/
public class RunOracleExistingJobExample { private static Logger LOG = LoggerFactory.getLogger(RunOracleExistingJobExample.class); public void run(boolean inClearJobs) throws Exception { // 初始化调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler(); if (inClearJobs) {
sched.clear();
LOG.warn("***** Deleted existing jobs/triggers *****");
} LOG.info("------- Starting Scheduler ---------------");
sched.start();
try {
Thread.sleep(3600L * 1000L);
} catch (Exception e) {
//
} sched.shutdown();
LOG.info("------- Shutdown Complete ----------------");
} public static void main(String[] args) throws Exception {
boolean clearJobs = false; // 是否清空job任务,这里为不清空 RunOracleExistingJobExample example = new RunOracleExistingJobExample();
example.run(clearJobs);
}
}

quartz2.3.0(十五)执行、暂停、继续执行、清除,花式操作数据库中持久化的job任务的更多相关文章

  1. 孤荷凌寒自学python第五十二天初次尝试使用python读取Firebase数据库中记录

    孤荷凌寒自学python第五十二天初次尝试使用python读取Firebase数据库中记录 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数 ...

  2. 【hibernate spring data jpa】执行了save()方法 sql语句也执行了,但是数据并未插入数据库中

    执行了save()方法  sql语句也执行了,但是数据并未插入数据库中 解决方法: 是因为执行了save()方法,也执行了sql语句,但是因为使用的是 @Transactional 注解,不是手动去提 ...

  3. Java-JUC(十五):synchronized执行流程分析

    一.锁对象及 synchronized 的使用 synchronized 通过互斥锁(Mutex Lock)来实现,同一时刻,只有获得锁的线程才可以执行锁内的代码. 锁对象分为两种: 实例对象(一个类 ...

  4. 从零开始学ios开发(十五):Navigation Controllers and Table Views(中)

    这篇内容我们继续上一篇的例子接着做下去,为其再添加3个table view的例子,有了之前的基础,学习下面的例子会变得很简单,很多东西都是举一反三,稍稍有些不同的内容,好了,闲话少说,开始这次的学习. ...

  5. ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    ExpandoObject与DynamicObject的使用   using ImpromptuInterface; using System; using System.Dynamic; names ...

  6. python语言(五)匿名函数、读写excel、操作数据库、加密、redis操作

    一.匿名函数 递归:就是调用自己 def func(): num = int(input('num:')) if num % 2 ==0: print('是偶数') return else: func ...

  7. quartz2.3.0(五)制定错过执行任务的misfire策略,用pause,resume模拟job暂停执行和继续执行

    感谢兄台: <quartz-misfire 错失.补偿执行> misfire定义 misfire:被错过的执行任务策略 misfire重现——CronTrigger job任务类: pac ...

  8. 第十五篇:使用 FP-growth 算法高效挖掘海量数据中的频繁项集

    前言 对于如何发现一个数据集中的频繁项集,前文讲解的经典 Apriori 算法能够做到. 然而,对于每个潜在的频繁项,它都要检索一遍数据集,这是比较低效的.在实际的大数据应用中,这么做就更不好了. 本 ...

  9. 十五、CI框架之自动加载数据库

    一.在config的autoload.php文件中,如果写入以下代码,那么在控制器中无需再次加载数据库了,相当于全局自动加载数据库了 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码 ...

随机推荐

  1. 稀疏矩阵的存储(c++)

    0        0        0        0        0         0 0        3        0        0        0         0 0    ...

  2. ICEM-一种网格画法的思考

    原视频下载链接:https://pan.baidu.com/s/1kV4Zj3x 密码: uthc

  3. CodeMirror在线代码编辑器使用

    CodeMirror官网地址为:https://codemirror.net/ CodeMirror作为一款代码编辑器,其应用场景主要是在线网站写代码.如现在的leetcode.洛谷.code-vs等 ...

  4. CTF 文件包含

    目录 一.基本概念 二.本地文件包含 三.远程文件包含 四.具体场景 五.补充 一.基本概念 文件包含 将相同函数写入单独的文件中,需要使用时直接调用 文件包含漏洞 将被包含的文件设置为变量,导致客户 ...

  5. Oracle存储过程 函数 计算使用资源

    目录 存储过程与函数 存储过程的优势 存储过程 打印语句 选择语句 函数 计算使用资源 存储过程与函数 存储过程的优势 存储过程 /* 多行注释 */ -- 单行注释 //展示错误信息 show er ...

  6. RocketMQ官方启动脚本不支持jdk11的修改

    以rocketmq4.5.0为例 主要涉及classpath和启动配置. nameserver: vim /opt/rocketmq/bin/runserver.sh 删除 -XX:+UseConcM ...

  7. 如何使用Salt Pillar

    作者言 Salt的网站上有两篇关于Pillar的文档(一,二),其中一篇内容很少,我觉得写成一篇文章更合适.本文的逻辑结构没有参照官方文档,而是根据我自己对Pillar的理解组织内容,希望能够把这个概 ...

  8. Tracking without bells and whistles

    Tracking without bells and whistles 2019-08-07 20:46:12 Paper: https://arxiv.org/pdf/1903.05625 Code ...

  9. Java多线程的Semaphore

    Semaphore 信号量, 在多线程应用中, 用来控制同时访问某个特定资源的操作数量, 或者同时执行某个指定操作的数量, 还可以用来实现某种资源池限制, 或者对容器施加边界. 简单地说, Semap ...

  10. 关于idea跳过错误编译的理解, 跳过报错的代码启动项目去debug测试其他正常的代码

    关于idea跳过错误编译的理解 2018年07月13日 19:06:32 weixin_39669410 阅读数 1296   其实idea使用eclipse编译器可以实现跳过报错的代码启动项目去de ...