Quartz.NET 数据库 Schema 完全指南:AdoJobStore 表结构、触发器状态与迁移路径
发布时间:2026/10/6 15:52:23 作者:尧图编辑部 阅读量:1,286

任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载Quartz.NET 的持久化作业存储ADO.NET Job Store通常为JobStoreTX依赖一组预定义的数据表来保存作业、触发器、日历与调度状态。本文以官方文档《Database Schema》为骨架逐表拆解这组表的职责与关键列厘清TriggerState各状态的语义含仅存在于数据库层的状态字面量并给出全新安装建表与存量库升级迁移的完整实操路径帮你一次性掌握 Quartz.NET 持久化存储的表 状态 迁移全貌。AdoJobStore 的前提Quartz 不会替你建表使用基于 ADO.NET 的作业存储通常选择JobStoreTX时Quartz.NET 本身不会创建或迁移数据库表。你需要自行执行建表脚本创建 Schema并在版本升级时自行执行迁移脚本。这一点在官方文档《Database Schema》中明确声明仓库内 database/README.md 也再次强调迁移既有 Schema 永远是手动步骤Quartz 内部没有任何机制替你完成4.x 的ProvisionSchema()只能创建缺失的表不能为已存在的表补列。因此围绕数据库的实操共有三种场景对应仓库database/目录下三类资源| 场景 | 使用资源 | 位置 | | -- | -- | -- | | 全新安装 | 建表脚本每库一个创建当前完整 Schema | database/tables/ | | 存量库升级 | 迁移脚本按 Quartz.NET 版本分文件夹 | database/migrations/ | | 自动预置4.x | 内嵌于Quartz.dll的create_dialect.sql| src/Quartz/Impl/AdoJobStore/Schema/ |后文将按表结构 → 触发状态 → 建表 → 迁移的顺序展开。核心表清单11 张表各司其职官方文档给出的表清单如下表名均以默认前缀QRTZ_开头前缀可自定义只要通过quartz.jobStore.tablePrefix告知 JobStore 即可| 表 | 简要职责 | | -- | -- | |qrtz_calendars| 存储非标准日历Calendar | |qrtz_job_details| 存储IJobDetail数据 | |qrtz_locks| Quartz 使用的锁 | |qrtz_scheduler_state| 存储IScheduler数据集群心跳/检查点 | |qrtz_triggers| 存储ITrigger数据所有触发器类型的公共字段 | |qrtz_cron_triggers| 存储 CRON 触发器的 cron 表达式 | |qrtz_fired_triggers| 当前正在运行的触发器 | |qrtz_blob_triggers| 以二进制 Blob 存储触发器数据的表 | |qrtz_simple_triggers| 非常简单的重复触发器的数据 | |qrtz_simprop_triggers| 自定义触发器的可复用表ICalendarIntervalTrigger、IDailyTimeIntervalTrigger以及3.18 起IRecurrenceTrigger使用它 | |qrtz_paused_trigger_grps|IScheduler.PauseTriggers产生的数据 |结合仓库中实际的建表脚本以 database/tables/tables_postgres.sql 为例其他方言结构一致可以进一步理解表的关联关系qrtz_job_details以(sched_name, job_name, job_group)为主键除名称与描述外还包含job_class_name作业类全名、is_durable持久作业、is_nonconcurrent对应DisallowConcurrentExecutionAttribute、is_update_data对应PersistJobDataAfterExecutionAttribute、requests_recovery故障恢复以及job_dataJobDataMap的序列化负载。qrtz_triggers是所有触发器类型的公共父表通过(sched_name, job_name, job_group)外键引用qrtz_job_details。qrtz_simple_triggers/qrtz_cron_triggers/qrtz_simprop_triggers/qrtz_blob_triggers均以(sched_name, trigger_name, trigger_group)为主键并通过相同键外键引用qrtz_triggersON DELETE CASCADE删除父触发器时级联清理子表分别保存各触发器类型的专属字段simple表存repeat_count、repeat_interval、times_triggeredcron表存cron_expression与time_zone_idsimprop表是一组可空的通用属性列str_prop_1..3、int_prop_1..2、long_prop_1..2、dec_prop_1..2、bool_prop_1..2、time_zone_idblob表只有一个blob_data列。qrtz_fired_triggers记录正在执行的触发器(sched_name, entry_id)为主键额外保存instance_name哪个节点在执行、fired_time、sched_time计划触发时间2.2 起加入供恢复作业同时看到计划时间与实际触发时间。qrtz_scheduler_state保存集群中各调度器实例的last_checkin_time与checkin_interval是集群故障检测的基础。qrtz_locks保存 Quartz 使用的锁名如触发器访问锁、状态同步锁配合行锁实现集群内的并发控制。qrtz_calendars以(sched_name, calendar_name)为主键calendar列存储序列化后的日历对象。注意4.x 的建表脚本还在上述 11 张表之外新增了qrtz_paused_job_grps暂停的作业组、qrtz_execution_history与qrtz_misfire_history执行历史仅在使用UseExecutionHistory()时读写详见 database/tables/tables_postgres.sql 第 154–229 行。Quartz Triggers 表所有触发器的公共字段官方文档单独强调了qrtz_triggers表它存储所有触发器类型共享的ITrigger数据。从 tables_postgres.sql 第 45–75 行可以看到这张表承载的核心字段| 字段 | 含义 | | -- | -- | |sched_name| 调度器实例名多实例/多前缀共享库时的隔离键所有表的主键与索引都以它开头 | |trigger_name/trigger_group| 触发器键与sched_name组成主键 | |job_name/job_group| 关联的作业键外键到qrtz_job_details | |next_fire_time/prev_fire_time| 下次/上次触发时间以 epoch 毫秒存储 | |priority| 触发优先级抢触发时排序用 | |trigger_state| 触发器当前状态见下一节 | |trigger_type| 触发器类型标记SIMPLE / CRON / SIMPROP / BLOB 等 | |start_time/end_time| 生效时间窗 | |calendar_name| 关联的日历名 | |misfire_instr| 失火指令 | |job_data|JobDataMap的序列化负载若usePropertiestrue则仅存字符串键值对 |后续版本陆续为这张表追加的列包括3.17 的misfire_orig_fire_time失火处理覆盖前的原始计划触发时间、3.18 的execution_group、3.19 的preferred_node/preferred_node_auto节点亲和性、4.0 的retry_policy/retry_attempt重试策略、4.2 的continues_trigger_name/continues_trigger_group/continuation_condition条件延续。这些列正是《Database Schema Changes》中各迁移版本的核心内容。触发器状态用户可见的 7 种状态官方文档用一张表概括了IScheduler向用户暴露的触发器状态| 状态 | 含义 | | -- | -- | |Normal| 触发器拥有触发时间将按计划执行 | |Paused| 已暂停不会执行 | |Complete| 触发器不再触发已无剩余触发时间 | |Error| 触发器发生错误将不再被触发 | |Blocked| 该触发器关联的作业带有DisallowConcurrentExecutionAttribute需等待但该触发器本应触发 | |None| 触发器不存在 | |Waiting| 仅存在于数据库层表示作业已准备好被拾取 |对照源码 src/Quartz/TriggerState.cs 可以确认这些状态的更深一层语义该枚举是线上的约定wire contractHTTP API 以枚举名返回状态、按名称接受状态过滤因此成员绝不能改名数值被作业存储持久化且仍被线上接受因此绝不能重新编号或调整顺序新成员只能追加。枚举当前共 8 个成员Normal 0、Paused 1、Complete 2、Error 3、Blocked 4、None 5、Executing 6、Awaiting 7。文档表格未列出的Executing表示该触发器启动的至少一次执行正在进行使用持久化作业存储时它像QueryFireInstances一样可跨集群各节点观察Awaiting表示触发器在存储层等待另一触发器的触发结束携带Continuation的触发器4.2 引入。细节补充暂停状态在已有执行仍在运行时优先上报Paused最终一次执行尚未结束时触发器上报Executing而非CompleteError通常源于作业类无法加载/执行失败调度器不会再尝试触发它。数据库层的额外状态WAITING、ACQUIRED、PAUSED_BLOCKED、AWAITING用户看到的TriggerState枚举并不等于数据库qrtz_triggers.trigger_state列中实际存储的全部字面量。在 src/Quartz/Impl/AdoJobStore/AdoConstants.cs 中可以看到 JobStore 持久化并使用的一系列数据库专用状态字符串| 常量 | 字面量 | 用途 | | -- | -- | -- | |StateWaiting|WAITING| 触发器等待被获取文档所述作业已准备好被拾取即此状态 | |StateAcquired|ACQUIRED| 触发器已被某节点获取、正在执行 | |StateBlocked|BLOCKED| 对应Blocked状态 | |StatePaused|PAUSED| 对应Paused状态 | |StatePausedBlocked|PAUSED_BLOCKED| 已暂停且被阻塞的组合状态 | |StateAwaiting|AWAITING| 等待被延续continuation解除4.2 起使用 |也就是说IScheduler.GetTriggerState返回的枚举是 JobStore 对数据库状态做映射后的用户视图而表里真实流转的状态还包括ACQUIRED、PAUSED_BLOCKED等。这正是为什么文档特别注明Waiting是db only状态——它不会以枚举形式暴露给调用方。全新安装如何建表首次部署持久化 JobStore 时直接运行 database/tables/ 下对应你所用数据库的脚本即可它创建的是当前完整 Schema包含后续所有迁移版本加入的列新库完全不需要执行任何迁移脚本。| 数据库 | 脚本 | | -- | -- | | SQL Server 2016 | tables/tables_sqlServer.sql | | SQL Server内存优化 | tables/tables_sqlServerMOT.sql | | SQL Server 2012/2014 | tables/tables_sqlServer_Below2016.sql | | PostgreSQL | tables/tables_postgres.sql | | MySQL / MariaDB | tables/tables_mysql_innodb.sql | | Oracle | tables/tables_oracle.sql | | SQLite | tables/tables_sqlite.sql | | Firebird | tables/tables_firebird.sql |执行建表脚本有几点务必注意见 database/README.md默认会先删除已存在的 Quartz Schema 再重建对生产库执行会销毁数据。想避免时将脚本中声明的DropDb变量改为0SQL Server 与 MySQL 上是DropDbSQLite 无变量需手动删除BEGIN DROP TABLES与END DROP TABLES之间的整块语句。SQL Server 脚本以USE [enter_db_name_here];开头必须把数据库名填进去否则会报Msg 911, Database enter_db_name_here does not exist其他方言不指定库名。建表脚本的CREATE TABLE不做存在性保护应只在没有 Quartz 表的库上运行。创建好表之后按 docs/documentation/quartz-3.x/tutorial/job-stores.md 中的步骤配置JobStoreTX、driverDelegateType如SqlServerDelegate、PostgreSQLDelegate、tablePrefix与数据源即可。表前缀默认QRTZ_可任意修改——不同的前缀可以让多个调度器实例的多套表共享同一个数据库。升级现有数据库按版本执行迁移存量库升级请参考《Database Schema Changes》它按版本列出了每一次 Schema 变更、应执行的迁移脚本以及跳过迁移的代价。迁移脚本按版本放在 database/migrations/ 的各子目录中每个目录内按数据库后缀选择文件_sqlServer、_postgres、_mysql_innodb、_oracle、_sqlite、_firebird文件可直接原样执行。选择迁移路径的速查表来自该文档| 从 | 到 | 需执行的迁移 | | -- | -- | -- | | 1.x | 任意 2.x/3.x | 2.0 → 2.2 → 2.6再按下面 3.x 处理 | | 2.0 / 2.1 | 3.x | 2.2 → 2.6 → 3.0再加可选的 3.x 项 | | 2.2–2.5 | 3.x | 2.6 → 3.0再加可选的 3.x 项 | | 2.6 | 3.x | 3.0再加可选的 3.x 项 | | 3.0–3.16 | 最新 3.x | 3.17 → 3.18 → 3.19 → 3.20均可选 | | 任意 3.x | 4.0 / 4.1 | 4.0强制且已包含 3.17 起的全部内容 | | 任意 3.x | 4.2 | 4.0 → 4.2均强制 | | 4.0 / 4.1 | 4.2 | 4.2强制 |执行迁移的三条铁律按升序执行当前与目标版本之间的每个版本一个都不能跳过。迁移是累积的而非互斥的跳过 3.17 直接跑 3.19最终仍会缺 3.17 的列没有脚本会回头补上。重复执行是安全的。除 SQL Server 1.0→2.0 的脚本外所有脚本在执行前都会检查重复运行等同 no-op半途中断的迁移也能重跑。唯一例外是 SQLite 的ADD COLUMNSQLite 不支持条件 DDL二次运行会失败。全新安装不需要这些。database/tables/ 的脚本已包含全部变更。各版本变更要点速览详见 schema-changes.md2.01.x → 2.x 的 Schema 重构仅 SQL Server 示例脚本需改造用于其他库删除 listener 表、varchar(1)标志列改为bit、IS_STATEFUL被IS_NONCONCURRENT/IS_UPDATE_DATA取代、SCHED_NAME加入所有表并重建主键与索引。注意该脚本将SCHED_NAME默认为TestScheduler有存量数据时必须改为与quartz.scheduler.instanceName一致。2.2QRTZ_FIRED_TRIGGERS增加SCHED_TIME恢复作业可同时看到计划与实际触发时间。该列NOT NULL且无默认值表中有行时ALTER会失败需先停调度器并执行DELETE FROM QRTZ_FIRED_TRIGGERS;。2.6QRTZ_SIMPROP_TRIGGERS与QRTZ_CRON_TRIGGERS增加TIME_ZONE_ID让触发器时区在重启后存活。若很久以前升级过 2.5→2.6请检查两表是否都有该列早期版本只改了 simprop 表。3.0仅 SQL Server废弃的IMAGE列转为VARBINARY(MAX)涉及QRTZ_CALENDARS.CALENDAR、QRTZ_JOB_DETAILS.JOB_DATA、QRTZ_BLOB_TRIGGERS.BLOB_DATA、QRTZ_TRIGGERS.JOB_DATA。3.17QRTZ_TRIGGERS增加MISFIRE_ORIG_FIRE_TIME记录失火处理覆盖前的原始计划触发时间。跳过则立即触发类失火策略下ScheduledFireTimeUtc会等于FireTimeUtcRAMJobStore不受影响。3.18QRTZ_TRIGGERS与QRTZ_FIRED_TRIGGERS都增加EXECUTION_GROUP执行组。跳过则执行组限制退化为获取后的内存过滤节点会获取到本不必取的触发器再放回。3.19QRTZ_TRIGGERS增加PREFERRED_NODE与PREFERRED_NODE_AUTO节点亲和性。两列必须同时加Quartz 仅在两者都存在时才启用节点亲和性。3.20仅性能优化。按 AdoJobStore 实际发出的语句重新对齐索引集每句 SQL 都先过滤SCHED_NAME但部分旧索引未以其开头PostgreSQL 最严重11 个索引中 9 个受影响且IDX_QRTZ_T_NFT_ST列序错误。SQLite 此前无二级索引每次获取轮询都是全表扫描此次补上。4.0强制且是唯一不可推迟的迁移。3.x 在启动时探测上述四列是否存在缺失则警告并关闭对应功能4.x 移除探测、假定四列齐全并新增 3.x 从未有过的RETRY_POLICY/RETRY_ATTEMPTQRTZ_TRIGGERS均可空、无默认值存量行自动视为无重试策略与QRTZ_PAUSED_JOB_GRPS表记录暂停的作业组3.x 暂停作业组不落库导致重启后丢失。4.x 启动时校验所需表可查询并逐列执行SELECT column … WHERE 1 0探测缺失即拒绝启动并指明列名与脚本。4.0 迁移包含两个文件schema_30_to_40_upgrade_db.sql强制3.x 节点在线时即可安全执行与schema_30_to_40_indexes_db.sql可选仅性能须等最后一个 3.x 节点下线后再执行因为它会删除 3.x 失火扫描依赖的IDX_QRTZ_T_NFT_ST_MISFIRE并把获取索引IDX_QRTZ_T_NFT_ST重塑为(SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME ASC, PRIORITY DESC, MISFIRE_INSTR)Firebird 因整索引只能单一方向而保持三列版本。4.2add_continuations_db.sql强制为QRTZ_TRIGGERS增加CONTINUES_TRIGGER_NAME、CONTINUES_TRIGGER_GROUP、CONTINUATION_CONDITION条件延续CONTINUATION_CONDITION标志位1 成功、2 失败、4 取消、8 否决、15 无论如何结束都放行等待中的触发器处于新状态AWAITING且不会被获取由父触发器的完成事件在父锁与事务内解除或删除add_execution_history_db.sql可选仅UseExecutionHistory()需要创建QRTZ_EXECUTION_HISTORY与QRTZ_MISFIRE_HISTORY两张历史表。滚动升级时先执行迁移、再把所有节点滚动到 4.2、最后才开始调度延续——4.1 节点无法解除延续且会把AWAITING行当作普通状态处理。迁移脚本目录的版本文件均可直接查看例如 database/migrations/4.0/schema_30_to_40_upgrade_postgres.sql 与 database/migrations/4.0/schema_30_to_40_indexes_postgres.sql。官方文档同时提醒务必先在测试环境对生产库的副本执行迁移脚本。小结Quartz.NET 的持久化存储可以概括为一套表 两类状态 两条脚本路径一套表qrtz_triggers作为公共父表配合qrtz_simple/cron/simprop/blob_triggers四个子表覆盖全部触发器类型另有作业、日历、锁、调度状态、运行中触发器与暂停组等配套表两类状态面向用户的TriggerState枚举Normal/Paused/Complete/Error/Blocked/None外加Executing、Awaiting与数据库层的流转字面量WAITING/ACQUIRED/PAUSED_BLOCKED等定义于 AdoConstants.cs两条脚本路径全新安装用 database/tables/存量升级用 database/migrations/二者井水不犯河水——升级只能靠迁移脚本建表脚本与ProvisionSchema()都不能为已存在的表补列。把握住这三条主线无论是排查触发器状态与预期不符的疑难、规划集群库的索引优化还是筹备 3.x → 4.x / 4.1 → 4.2 的升级你都能在 docs/documentation/database/schema-changes.md 与 database/README.md 中找到对应依据并落到仓库中逐行可读的 SQL 脚本上。赞分享任务调度后端【免费下载链接】quartznetQuartz Enterprise Scheduler .NET项目地址https://gitcode.com/gh_mirrors/qu/quartznet点击查看免费下载相关推荐Quartz.NET 数据库 Schema 迁移完整指南从 1.x 到 4.2 的升级路径与脚本详解Quartz.NET 数据库 Schema 迁移完整指南从 1.x 到 4.2 的升级路径与脚本详解 导读 Quartz.NET 从不自动迁移你的数据库 S任务调度后端Quartz.NET JobStore 完全指南RAMJobStore 与 AdoJobStore 配置、数据库建表与持久化原理Quartz.NET JobStore 完全指南RAMJobStore 与 AdoJobStore 配置、数据库建表与持久化原理 本指南围绕 Quartz.N任务调度后端Quartz.NET 数据库脚本完全指南全新安装、Schema 自动创建与版本迁移Quartz.NET 数据库脚本完全指南全新安装、Schema 自动创建与版本迁移 本文基于 database/README.md https://link.任务调度后端上一篇高级技巧在reka.js中集成外部函数与动态数据处理下一篇React TypeScript 组件库开发完整教程蚂蚁数据团队经验分享创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考