├── .gitignore
├── pom.xml
├── readme.md
└── src
└── main
├── java
└── com
│ └── github
│ ├── QuartzSimpleApplication.java
│ ├── domain
│ ├── entity
│ │ └── TaskDefine.java
│ ├── execute
│ │ └── SayHelloJobLogic.java
│ └── service
│ │ └── QuartzJobService.java
│ └── interfaces
│ └── JobInterfaces.java
└── resources
├── application.yml
└── schema.sql
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 | * Job 是 定时任务的具体执行逻辑 14 | * JobDetail 是 定时任务的定义 15 | */ 16 | @DisallowConcurrentExecution 17 | public class SayHelloJobLogic implements Job { 18 | private static final Logger log = LoggerFactory.getLogger(SayHelloJobLogic.class); 19 | 20 | @Override 21 | public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { 22 | //写你自己的逻辑 23 | log.info("SayHelloJob.execute , hello world ! "); 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/domain/service/QuartzJobService.java: -------------------------------------------------------------------------------- 1 | package com.github.domain.service; 2 | 3 | import com.github.domain.entity.TaskDefine; 4 | import org.quartz.*; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.scheduling.quartz.SchedulerFactoryBean; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * Created by EalenXie on 2019/7/10 13:49. 15 | * 核心其实就是Scheduler的功能 , 这里只是非常简单的示例说明其功能 16 | * 如需根据自身业务进行扩展 请参考 {@link org.quartz.Scheduler} 17 | */ 18 | 19 | @Service 20 | public class QuartzJobService { 21 | 22 | private static final Logger log = LoggerFactory.getLogger(QuartzJobService.class); 23 | 24 | //Quartz定时任务核心的功能实现类 25 | private final Scheduler scheduler; 26 | 27 | public QuartzJobService(@Autowired SchedulerFactoryBean schedulerFactoryBean) { 28 | scheduler = schedulerFactoryBean.getScheduler(); 29 | } 30 | 31 | /** 32 | * 创建和启动 定时任务 33 | * {@link org.quartz.Scheduler#scheduleJob(JobDetail, Trigger)} 34 | * 35 | * @param define 定时任务 36 | */ 37 | public void scheduleJob(TaskDefine define) throws SchedulerException { 38 | //1.定时任务 的 名字和组名 39 | JobKey jobKey = define.getJobKey(); 40 | //2.定时任务 的 元数据 41 | JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap()); 42 | //3.定时任务 的 描述 43 | String description = define.getDescription(); 44 | //4.定时任务 的 逻辑实现类 45 | Class extends Job> jobClass = define.getJobClass(); 46 | //5.定时任务 的 cron表达式 47 | String cron = define.getCronExpression(); 48 | JobDetail jobDetail = getJobDetail(jobKey, description, jobDataMap, jobClass); 49 | Trigger trigger = getTrigger(jobKey, description, jobDataMap, cron); 50 | scheduler.scheduleJob(jobDetail, trigger); 51 | } 52 | 53 | 54 | /** 55 | * 暂停Job 56 | * {@link org.quartz.Scheduler#pauseJob(JobKey)} 57 | */ 58 | public void pauseJob(JobKey jobKey) throws SchedulerException { 59 | scheduler.pauseJob(jobKey); 60 | } 61 | 62 | /** 63 | * 恢复Job 64 | * {@link org.quartz.Scheduler#resumeJob(JobKey)} 65 | */ 66 | public void resumeJob(JobKey jobKey) throws SchedulerException { 67 | scheduler.resumeJob(jobKey); 68 | } 69 | 70 | /** 71 | * 删除Job 72 | * {@link org.quartz.Scheduler#deleteJob(JobKey)} 73 | */ 74 | public void deleteJob(JobKey jobKey) throws SchedulerException { 75 | scheduler.deleteJob(jobKey); 76 | } 77 | 78 | 79 | /** 80 | * 修改Job 的cron表达式 81 | */ 82 | public boolean modifyJobCron(TaskDefine define) { 83 | String cronExpression = define.getCronExpression(); 84 | //1.如果cron表达式的格式不正确,则返回修改失败 85 | if (!CronExpression.isValidExpression(cronExpression)) return false; 86 | JobKey jobKey = define.getJobKey(); 87 | TriggerKey triggerKey = new TriggerKey(jobKey.getName(), jobKey.getGroup()); 88 | try { 89 | CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); 90 | JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap()); 91 | //2.如果cron发生变化了,则按新cron触发 进行重新启动定时任务 92 | if (!cronTrigger.getCronExpression().equalsIgnoreCase(cronExpression)) { 93 | CronTrigger trigger = TriggerBuilder.newTrigger() 94 | .withIdentity(triggerKey) 95 | .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) 96 | .usingJobData(jobDataMap) 97 | .build(); 98 | scheduler.rescheduleJob(triggerKey, trigger); 99 | } 100 | } catch (SchedulerException e) { 101 | log.error("printStackTrace", e); 102 | return false; 103 | } 104 | return true; 105 | } 106 | 107 | 108 | /** 109 | * 获取定时任务的定义 110 | * JobDetail是任务的定义,Job是任务的执行逻辑 111 | * 112 | * @param jobKey 定时任务的名称 组名 113 | * @param description 定时任务的 描述 114 | * @param jobDataMap 定时任务的 元数据 115 | * @param jobClass {@link org.quartz.Job} 定时任务的 真正执行逻辑定义类 116 | */ 117 | public JobDetail getJobDetail(JobKey jobKey, String description, JobDataMap jobDataMap, Class extends Job> jobClass) { 118 | return JobBuilder.newJob(jobClass) 119 | .withIdentity(jobKey) 120 | .withDescription(description) 121 | .setJobData(jobDataMap) 122 | .usingJobData(jobDataMap) 123 | .requestRecovery() 124 | .storeDurably() 125 | .build(); 126 | } 127 | 128 | 129 | /** 130 | * 获取Trigger (Job的触发器,执行规则) 131 | * 132 | * @param jobKey 定时任务的名称 组名 133 | * @param description 定时任务的 描述 134 | * @param jobDataMap 定时任务的 元数据 135 | * @param cronExpression 定时任务的 执行cron表达式 136 | */ 137 | public Trigger getTrigger(JobKey jobKey, String description, JobDataMap jobDataMap, String cronExpression) { 138 | return TriggerBuilder.newTrigger() 139 | .withIdentity(jobKey.getName(), jobKey.getGroup()) 140 | .withDescription(description) 141 | .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) 142 | .usingJobData(jobDataMap) 143 | .build(); 144 | } 145 | 146 | 147 | public JobDataMap getJobDataMap(Map, ?> map) { 148 | return map == null ? new JobDataMap() : new JobDataMap(map); 149 | } 150 | 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/com/github/interfaces/JobInterfaces.java: -------------------------------------------------------------------------------- 1 | package com.github.interfaces; 2 | 3 | import com.github.domain.entity.TaskDefine; 4 | import com.github.domain.execute.SayHelloJobLogic; 5 | import com.github.domain.service.QuartzJobService; 6 | import org.quartz.JobKey; 7 | import org.quartz.SchedulerException; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import javax.annotation.Resource; 12 | 13 | /** 14 | * Created by EalenXie on 2019/7/10 16:01. 15 | */ 16 | @RestController 17 | public class JobInterfaces { 18 | 19 | 20 | @Resource 21 | private QuartzJobService quartzJobService; 22 | 23 | 24 | //假如 这个定时任务的 名字叫做HelloWorld, 组名GroupOne 25 | private final JobKey jobKey = JobKey.jobKey("HelloWorld", "GroupOne"); 26 | 27 | /** 28 | * 启动 hello world 29 | */ 30 | @GetMapping("/start") 31 | public String startHelloWorldJob() throws SchedulerException { 32 | 33 | //创建一个定时任务 34 | TaskDefine task = new TaskDefine(jobKey, 35 | "这是一个测试的 任务", //定时任务 的描述 36 | "0/2 * * * * ? ", //定时任务 的cron表达式 37 | null, 38 | SayHelloJobLogic.class //定时任务 的具体执行逻辑 39 | ); 40 | quartzJobService.scheduleJob(task); 41 | return "start HelloWorld Job success"; 42 | } 43 | 44 | /** 45 | * 暂停 hello world 46 | */ 47 | @GetMapping("/pause") 48 | public String pauseHelloWorldJob() throws SchedulerException { 49 | quartzJobService.pauseJob(jobKey); 50 | return "pause HelloWorld Job success"; 51 | } 52 | 53 | 54 | /** 55 | * 恢复 hello world 56 | */ 57 | @GetMapping("/resume") 58 | public String resumeHelloWorldJob() throws SchedulerException { 59 | quartzJobService.resumeJob(jobKey); 60 | return "resume HelloWorld Job success"; 61 | } 62 | 63 | /** 64 | * 删除 hello world 65 | */ 66 | @GetMapping("/delete") 67 | public String deleteHelloWorldJob() throws SchedulerException { 68 | quartzJobService.deleteJob(jobKey); 69 | return "delete HelloWorld Job success"; 70 | } 71 | 72 | /** 73 | * 修改 hello world 的cron表达式 74 | */ 75 | @GetMapping("/modifyCron") 76 | public String modifyHelloWorldJobCron() { 77 | //这是即将要修改cron的定时任务 78 | TaskDefine task = new TaskDefine(jobKey, 79 | "这是一个测试的 任务", //定时任务 的描述 80 | "0/5 * * * * ? ", //定时任务 的cron表达式 81 | null, 82 | SayHelloJobLogic.class //定时任务 的具体执行逻辑 83 | ); 84 | if (quartzJobService.modifyJobCron(task)) 85 | return "modify HelloWorld Job Cron success"; 86 | else return "modify HelloWorld Job Cron fail"; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: springboot-quartz-simple 4 | 5 | # quartz 相关属性配置 6 | quartz: 7 | properties: 8 | org: 9 | quartz: 10 | scheduler: 11 | instanceName: clusteredScheduler 12 | instanceId: AUTO 13 | jobStore: 14 | class: org.quartz.impl.jdbcjobstore.JobStoreTX 15 | driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate 16 | tablePrefix: QRTZ_ 17 | isClustered: true 18 | clusterCheckinInterval: 10000 19 | useProperties: false 20 | threadPool: 21 | class: org.quartz.simpl.SimpleThreadPool 22 | threadCount: 10 23 | threadPriority: 5 24 | threadsInheritContextClassLoaderOfInitializingThread: true 25 | #数据库方式 26 | job-store-type: jdbc 27 | -------------------------------------------------------------------------------- /src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | -- Thanks to Amir Kibbar and Peter Rietzler for contributing the schema for H2 database, 2 | -- and verifying that it works with Quartz's StdJDBCDelegate 3 | -- 4 | -- Note, Quartz depends on row-level locking which means you must use the MVCC=TRUE 5 | -- setting on your H2 database, or you will experience dead-locks 6 | -- 7 | -- 8 | -- In your Quartz properties file, you'll need to set 9 | -- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate 10 | 11 | CREATE TABLE QRTZ_CALENDARS 12 | ( 13 | SCHED_NAME VARCHAR(120) NOT NULL, 14 | CALENDAR_NAME VARCHAR(200) NOT NULL, 15 | CALENDAR IMAGE NOT NULL 16 | ); 17 | 18 | CREATE TABLE QRTZ_CRON_TRIGGERS 19 | ( 20 | SCHED_NAME VARCHAR(120) NOT NULL, 21 | TRIGGER_NAME VARCHAR(200) NOT NULL, 22 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 23 | CRON_EXPRESSION VARCHAR(120) NOT NULL, 24 | TIME_ZONE_ID VARCHAR(80) 25 | ); 26 | 27 | CREATE TABLE QRTZ_FIRED_TRIGGERS 28 | ( 29 | SCHED_NAME VARCHAR(120) NOT NULL, 30 | ENTRY_ID VARCHAR(95) NOT NULL, 31 | TRIGGER_NAME VARCHAR(200) NOT NULL, 32 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 33 | INSTANCE_NAME VARCHAR(200) NOT NULL, 34 | FIRED_TIME BIGINT NOT NULL, 35 | SCHED_TIME BIGINT NOT NULL, 36 | PRIORITY INTEGER NOT NULL, 37 | STATE VARCHAR(16) NOT NULL, 38 | JOB_NAME VARCHAR(200) NULL, 39 | JOB_GROUP VARCHAR(200) NULL, 40 | IS_NONCONCURRENT BOOLEAN NULL, 41 | REQUESTS_RECOVERY BOOLEAN NULL 42 | ); 43 | 44 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS 45 | ( 46 | SCHED_NAME VARCHAR(120) NOT NULL, 47 | TRIGGER_GROUP VARCHAR(200) NOT NULL 48 | ); 49 | 50 | CREATE TABLE QRTZ_SCHEDULER_STATE 51 | ( 52 | SCHED_NAME VARCHAR(120) NOT NULL, 53 | INSTANCE_NAME VARCHAR(200) NOT NULL, 54 | LAST_CHECKIN_TIME BIGINT NOT NULL, 55 | CHECKIN_INTERVAL BIGINT NOT NULL 56 | ); 57 | 58 | CREATE TABLE QRTZ_LOCKS 59 | ( 60 | SCHED_NAME VARCHAR(120) NOT NULL, 61 | LOCK_NAME VARCHAR(40) NOT NULL 62 | ); 63 | 64 | CREATE TABLE QRTZ_JOB_DETAILS 65 | ( 66 | SCHED_NAME VARCHAR(120) NOT NULL, 67 | JOB_NAME VARCHAR(200) NOT NULL, 68 | JOB_GROUP VARCHAR(200) NOT NULL, 69 | DESCRIPTION VARCHAR(250) NULL, 70 | JOB_CLASS_NAME VARCHAR(250) NOT NULL, 71 | IS_DURABLE BOOLEAN NOT NULL, 72 | IS_NONCONCURRENT BOOLEAN NOT NULL, 73 | IS_UPDATE_DATA BOOLEAN NOT NULL, 74 | REQUESTS_RECOVERY BOOLEAN NOT NULL, 75 | JOB_DATA IMAGE NULL 76 | ); 77 | 78 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS 79 | ( 80 | SCHED_NAME VARCHAR(120) NOT NULL, 81 | TRIGGER_NAME VARCHAR(200) NOT NULL, 82 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 83 | REPEAT_COUNT BIGINT NOT NULL, 84 | REPEAT_INTERVAL BIGINT NOT NULL, 85 | TIMES_TRIGGERED BIGINT NOT NULL 86 | ); 87 | 88 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS 89 | ( 90 | SCHED_NAME VARCHAR(120) NOT NULL, 91 | TRIGGER_NAME VARCHAR(200) NOT NULL, 92 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 93 | STR_PROP_1 VARCHAR(512) NULL, 94 | STR_PROP_2 VARCHAR(512) NULL, 95 | STR_PROP_3 VARCHAR(512) NULL, 96 | INT_PROP_1 INTEGER NULL, 97 | INT_PROP_2 INTEGER NULL, 98 | LONG_PROP_1 BIGINT NULL, 99 | LONG_PROP_2 BIGINT NULL, 100 | DEC_PROP_1 NUMERIC(13, 4) NULL, 101 | DEC_PROP_2 NUMERIC(13, 4) NULL, 102 | BOOL_PROP_1 BOOLEAN NULL, 103 | BOOL_PROP_2 BOOLEAN NULL 104 | ); 105 | 106 | CREATE TABLE QRTZ_BLOB_TRIGGERS 107 | ( 108 | SCHED_NAME VARCHAR(120) NOT NULL, 109 | TRIGGER_NAME VARCHAR(200) NOT NULL, 110 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 111 | BLOB_DATA IMAGE NULL 112 | ); 113 | 114 | CREATE TABLE QRTZ_TRIGGERS 115 | ( 116 | SCHED_NAME VARCHAR(120) NOT NULL, 117 | TRIGGER_NAME VARCHAR(200) NOT NULL, 118 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 119 | JOB_NAME VARCHAR(200) NOT NULL, 120 | JOB_GROUP VARCHAR(200) NOT NULL, 121 | DESCRIPTION VARCHAR(250) NULL, 122 | NEXT_FIRE_TIME BIGINT NULL, 123 | PREV_FIRE_TIME BIGINT NULL, 124 | PRIORITY INTEGER NULL, 125 | TRIGGER_STATE VARCHAR(16) NOT NULL, 126 | TRIGGER_TYPE VARCHAR(8) NOT NULL, 127 | START_TIME BIGINT NOT NULL, 128 | END_TIME BIGINT NULL, 129 | CALENDAR_NAME VARCHAR(200) NULL, 130 | MISFIRE_INSTR SMALLINT NULL, 131 | JOB_DATA IMAGE NULL 132 | ); 133 | 134 | ALTER TABLE QRTZ_CALENDARS 135 | ADD 136 | CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY 137 | ( 138 | SCHED_NAME, 139 | CALENDAR_NAME 140 | ); 141 | 142 | ALTER TABLE QRTZ_CRON_TRIGGERS 143 | ADD 144 | CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY 145 | ( 146 | SCHED_NAME, 147 | TRIGGER_NAME, 148 | TRIGGER_GROUP 149 | ); 150 | 151 | ALTER TABLE QRTZ_FIRED_TRIGGERS 152 | ADD 153 | CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY 154 | ( 155 | SCHED_NAME, 156 | ENTRY_ID 157 | ); 158 | 159 | ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS 160 | ADD 161 | CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY 162 | ( 163 | SCHED_NAME, 164 | TRIGGER_GROUP 165 | ); 166 | 167 | ALTER TABLE QRTZ_SCHEDULER_STATE 168 | ADD 169 | CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY 170 | ( 171 | SCHED_NAME, 172 | INSTANCE_NAME 173 | ); 174 | 175 | ALTER TABLE QRTZ_LOCKS 176 | ADD 177 | CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY 178 | ( 179 | SCHED_NAME, 180 | LOCK_NAME 181 | ); 182 | 183 | ALTER TABLE QRTZ_JOB_DETAILS 184 | ADD 185 | CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY 186 | ( 187 | SCHED_NAME, 188 | JOB_NAME, 189 | JOB_GROUP 190 | ); 191 | 192 | ALTER TABLE QRTZ_SIMPLE_TRIGGERS 193 | ADD 194 | CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY 195 | ( 196 | SCHED_NAME, 197 | TRIGGER_NAME, 198 | TRIGGER_GROUP 199 | ); 200 | 201 | ALTER TABLE QRTZ_SIMPROP_TRIGGERS 202 | ADD 203 | CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY 204 | ( 205 | SCHED_NAME, 206 | TRIGGER_NAME, 207 | TRIGGER_GROUP 208 | ); 209 | 210 | ALTER TABLE QRTZ_TRIGGERS 211 | ADD 212 | CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY 213 | ( 214 | SCHED_NAME, 215 | TRIGGER_NAME, 216 | TRIGGER_GROUP 217 | ); 218 | 219 | ALTER TABLE QRTZ_CRON_TRIGGERS 220 | ADD 221 | CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY 222 | ( 223 | SCHED_NAME, 224 | TRIGGER_NAME, 225 | TRIGGER_GROUP 226 | ) REFERENCES QRTZ_TRIGGERS ( 227 | SCHED_NAME, 228 | TRIGGER_NAME, 229 | TRIGGER_GROUP 230 | ) ON DELETE CASCADE; 231 | 232 | 233 | ALTER TABLE QRTZ_SIMPLE_TRIGGERS 234 | ADD 235 | CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY 236 | ( 237 | SCHED_NAME, 238 | TRIGGER_NAME, 239 | TRIGGER_GROUP 240 | ) REFERENCES QRTZ_TRIGGERS ( 241 | SCHED_NAME, 242 | TRIGGER_NAME, 243 | TRIGGER_GROUP 244 | ) ON DELETE CASCADE; 245 | 246 | ALTER TABLE QRTZ_SIMPROP_TRIGGERS 247 | ADD 248 | CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY 249 | ( 250 | SCHED_NAME, 251 | TRIGGER_NAME, 252 | TRIGGER_GROUP 253 | ) REFERENCES QRTZ_TRIGGERS ( 254 | SCHED_NAME, 255 | TRIGGER_NAME, 256 | TRIGGER_GROUP 257 | ) ON DELETE CASCADE; 258 | 259 | 260 | ALTER TABLE QRTZ_TRIGGERS 261 | ADD 262 | CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY 263 | ( 264 | SCHED_NAME, 265 | JOB_NAME, 266 | JOB_GROUP 267 | ) REFERENCES QRTZ_JOB_DETAILS ( 268 | SCHED_NAME, 269 | JOB_NAME, 270 | JOB_GROUP 271 | ); 272 | 273 | COMMIT; --------------------------------------------------------------------------------